From 89d83c084a74ff8694c6e1ae739ba8f86f5dc080 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Fri, 12 Apr 2024 23:52:08 +0800 Subject: [PATCH] Add new framework 'today' (#8815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add new framework Java/today * change build config * :arrow_up: 升级版本 4.0.0-Draft.6 * 更新 /updates API * 打开日志 * :fire: 删除 /updates API 偶尔会出错,目前尚未找到原因 * :art: 更新 /updates API * :art: 添加 epoll 支持 * :fire: remove all of the files that aren't necessary for the tests --- frameworks/Java/today/.gitignore | 9 ++ frameworks/Java/today/README.md | 26 ++++ frameworks/Java/today/benchmark_config.json | 30 +++++ frameworks/Java/today/build.gradle | 63 +++++++++ frameworks/Java/today/config.toml | 20 +++ frameworks/Java/today/gradle.properties | 7 + frameworks/Java/today/settings.gradle | 15 +++ .../cn/taketoday/benchmark/AppConfig.java | 70 ++++++++++ .../benchmark/BenchmarkApplication.java | 13 ++ .../benchmark/http/BenchmarkHttpHandler.java | 120 ++++++++++++++++++ .../cn/taketoday/benchmark/model/Fortune.java | 54 ++++++++ .../cn/taketoday/benchmark/model/World.java | 55 ++++++++ .../src/main/resources/application-dev.yaml | 9 ++ .../src/main/resources/application-test.yaml | 14 ++ .../today/src/main/resources/application.yaml | 41 ++++++ .../src/main/resources/templates/fortunes.ftl | 21 +++ frameworks/Java/today/today.dockerfile | 11 ++ 17 files changed, 578 insertions(+) create mode 100644 frameworks/Java/today/.gitignore create mode 100644 frameworks/Java/today/README.md create mode 100755 frameworks/Java/today/benchmark_config.json create mode 100644 frameworks/Java/today/build.gradle create mode 100644 frameworks/Java/today/config.toml create mode 100644 frameworks/Java/today/gradle.properties create mode 100644 frameworks/Java/today/settings.gradle create mode 100644 frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java create mode 100644 frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java create mode 100644 frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java create mode 100644 frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java create mode 100644 frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java create mode 100644 frameworks/Java/today/src/main/resources/application-dev.yaml create mode 100644 frameworks/Java/today/src/main/resources/application-test.yaml create mode 100644 frameworks/Java/today/src/main/resources/application.yaml create mode 100644 frameworks/Java/today/src/main/resources/templates/fortunes.ftl create mode 100644 frameworks/Java/today/today.dockerfile diff --git a/frameworks/Java/today/.gitignore b/frameworks/Java/today/.gitignore new file mode 100644 index 00000000000..ea1cbb085ef --- /dev/null +++ b/frameworks/Java/today/.gitignore @@ -0,0 +1,9 @@ +# Ignore Gradle project-specific cache directory +.gradle + +# Ignore Gradle build output directory +build + +.idea +today.properties +gradle \ No newline at end of file diff --git a/frameworks/Java/today/README.md b/frameworks/Java/today/README.md new file mode 100644 index 00000000000..a7c42243f25 --- /dev/null +++ b/frameworks/Java/today/README.md @@ -0,0 +1,26 @@ +# [TODAY Infrastructure](https://github.com/TAKETODAY/today-infrastructure) Benchmarking Test + +## Test URLs +### JSON + +http://localhost:8080/json + +### PLAINTEXT + +http://localhost:8080/plaintext + +### DB + +http://localhost:8080/db + +### QUERY + +http://localhost:8080/queries?queries= + +### UPDATE + +http://localhost:8080/update?queries= + +### FORTUNES + +http://localhost:8080/fortunes diff --git a/frameworks/Java/today/benchmark_config.json b/frameworks/Java/today/benchmark_config.json new file mode 100755 index 00000000000..92c3c756ad1 --- /dev/null +++ b/frameworks/Java/today/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "today", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "fortune_url": "/fortunes", + "update_url": "/updates?queries=", + "port": 8080, + "approach": "Realistic", + "classification": "Fullstack", + "database": "mysql", + "framework": "Today", + "language": "Java", + "flavor": "None", + "orm": "micro", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "Today", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/Java/today/build.gradle b/frameworks/Java/today/build.gradle new file mode 100644 index 00000000000..a95a1982f4e --- /dev/null +++ b/frameworks/Java/today/build.gradle @@ -0,0 +1,63 @@ +description = "benchmark" + +apply plugin: "java" +apply plugin: "application" +apply plugin: 'cn.taketoday.application' +apply plugin: 'io.spring.dependency-management' + +configure(allprojects) { + group = "cn.taketoday.benchmark" + + repositories { + mavenCentral() + maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } + } +} + +dependencies { + implementation 'cn.taketoday:today-starter-netty' + implementation 'cn.taketoday:today-starter-json' + implementation 'cn.taketoday:today-starter-jdbc' + implementation 'cn.taketoday:today-starter-web' + implementation 'cn.taketoday:today-starter-freemarker' + + implementation 'mysql:mysql-connector-java' + + implementation 'ch.qos.logback:logback-classic' + + implementation('io.netty:netty-transport-native-epoll') { + artifact { + classifier = 'linux-x86_64' + } + } + +// implementation('io.netty:netty-transport-native-kqueue') { +// artifact { +// classifier = 'osx-aarch_64' +// } +// } + +} + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +application { + mainClass = 'cn.taketoday.benchmark.BenchmarkApplication' + applicationDefaultJvmArgs = [ + "-server", + "-XX:+UseNUMA", + "-XX:+UseG1GC", + "-XX:+DisableExplicitGC", + "-XX:-StackTraceInThrowable", + "-XX:+UseStringDeduplication", + "-Dinfra.profiles.active=test", + "-Dio.netty.buffer.checkBounds=false", + "-Dio.netty.buffer.checkAccessible=false", + "-Dio.netty.leakDetection.level=disabled", + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED" + ] +} diff --git a/frameworks/Java/today/config.toml b/frameworks/Java/today/config.toml new file mode 100644 index 00000000000..dc2e84c877d --- /dev/null +++ b/frameworks/Java/today/config.toml @@ -0,0 +1,20 @@ +[framework] +name = "today" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +urls.db = "/db" +urls.query = "/queries?queries=" +urls.update = "/updates?queries=" +urls.fortune = "/fortunes" +approach = "Realistic" +classification = "Fullstack" +database = "mysql" +database_os = "Linux" +display_name = "today" +os = "Linux" +orm = "raw" +platform = "Netty" +webserver = "None" +versus = "None" diff --git a/frameworks/Java/today/gradle.properties b/frameworks/Java/today/gradle.properties new file mode 100644 index 00000000000..9379f1c95c9 --- /dev/null +++ b/frameworks/Java/today/gradle.properties @@ -0,0 +1,7 @@ +version=1.0.0 +#infraVersion=4.0.0-Draft.6-SNAPSHOT +infraVersion=4.0.0-Draft.6 + +org.gradle.caching=true +org.gradle.jvmargs=-Xmx2048m +org.gradle.parallel=true diff --git a/frameworks/Java/today/settings.gradle b/frameworks/Java/today/settings.gradle new file mode 100644 index 00000000000..8cb2bee3734 --- /dev/null +++ b/frameworks/Java/today/settings.gradle @@ -0,0 +1,15 @@ +buildscript { + repositories { + mavenLocal() + maven { + url "https://oss.sonatype.org/content/repositories/snapshots/" + } + mavenCentral() + } + + dependencies { + classpath "cn.taketoday:infra-gradle-plugin:$infraVersion" + } +} + +rootProject.name = 'today' diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java new file mode 100644 index 00000000000..1d385a77133 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java @@ -0,0 +1,70 @@ +package cn.taketoday.benchmark; + +import java.time.ZonedDateTime; + +import javax.sql.DataSource; + +import cn.taketoday.beans.factory.annotation.DisableAllDependencyInjection; +import cn.taketoday.beans.factory.config.BeanDefinition; +import cn.taketoday.context.annotation.Configuration; +import cn.taketoday.context.annotation.Role; +import cn.taketoday.framework.web.netty.NettyRequestConfig; +import cn.taketoday.framework.web.netty.SendErrorHandler; +import cn.taketoday.jdbc.RepositoryManager; +import cn.taketoday.jdbc.persistence.EntityManager; +import cn.taketoday.stereotype.Component; +import io.netty.handler.codec.http.DefaultHttpHeadersFactory; +import io.netty.handler.codec.http.HttpHeaders; +import io.netty.handler.codec.http.HttpHeadersFactory; +import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory; + +import static cn.taketoday.http.HttpHeaders.DATE_FORMATTER; + +/** + * @author Harry Yang + * @since 1.0 2024/3/19 12:59 + */ +@DisableAllDependencyInjection +@Role(BeanDefinition.ROLE_INFRASTRUCTURE) +@Configuration(proxyBeanMethods = false) +class AppConfig { + + private static final DefaultHttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory(); + + @Component + static RepositoryManager repositoryManager(DataSource dataSource) { + return new RepositoryManager(dataSource); + } + + @Component + static EntityManager entityManager(RepositoryManager repositoryManager) { + return repositoryManager.getEntityManager(); + } + + @Component + @Role(BeanDefinition.ROLE_INFRASTRUCTURE) + static NettyRequestConfig nettyRequestConfig(SendErrorHandler sendErrorHandler) { + var factory = new DefaultHttpDataFactory(false); + return NettyRequestConfig.forBuilder() + .httpDataFactory(factory) + .sendErrorHandler(sendErrorHandler) + .headersFactory(new HttpHeadersFactory() { + + @Override + public HttpHeaders newHeaders() { + HttpHeaders headers = headersFactory.newHeaders(); + headers.set("Server", "TODAY"); + headers.set("Date", DATE_FORMATTER.format(ZonedDateTime.now())); + return headers; + } + + @Override + public HttpHeaders newEmptyHeaders() { + return headersFactory.newEmptyHeaders(); + } + }) + .secure(false) + .build(); + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java new file mode 100644 index 00000000000..0e2eea0f995 --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java @@ -0,0 +1,13 @@ +package cn.taketoday.benchmark; + +import cn.taketoday.framework.Application; +import cn.taketoday.framework.InfraApplication; + +@InfraApplication +public class BenchmarkApplication { + + public static void main(String[] args) { + Application.run(BenchmarkApplication.class, args); + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java new file mode 100644 index 00000000000..d0d240534bd --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java @@ -0,0 +1,120 @@ +package cn.taketoday.benchmark.http; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +import cn.taketoday.benchmark.model.Fortune; +import cn.taketoday.benchmark.model.World; +import cn.taketoday.http.MediaType; +import cn.taketoday.http.ResponseEntity; +import cn.taketoday.jdbc.persistence.EntityManager; +import cn.taketoday.lang.Nullable; +import cn.taketoday.ui.Model; +import cn.taketoday.web.annotation.GET; +import cn.taketoday.web.annotation.RestController; +import cn.taketoday.web.view.ViewRef; + +/** + * @author Harry Yang + * @since 1.0 2024/3/19 12:56 + */ +@RestController +final class BenchmarkHttpHandler { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER = 10_000; + + private final EntityManager entityManager; + + BenchmarkHttpHandler(EntityManager entityManager) { + this.entityManager = entityManager; + } + + @GET("/json") + public ResponseEntity> json() { + return ResponseEntity.ok() + .contentType(MediaType.APPLICATION_JSON) + .body(Map.of("message", "Hello, World!")); + } + + @GET("/plaintext") + public String plaintext() { + return "Hello, World!"; + } + + @GET("/db") + public World db() { + return entityManager.findById(World.class, nextInt()); + } + + @GET("/queries") + public List queries(@Nullable String queries) { + return randomNumbers() + .mapToObj(this::findWorldById) + .limit(parseQueryCount(queries)) + .toList(); + } + + @GET("/updates") + public List updates(@Nullable String queries) { + return randomNumbers() + .mapToObj(this::findWorldById) + .filter(Objects::nonNull) + .peek(world -> { + world.setRandomNumber(nextInt()); + entityManager.updateById(world); + }) + .limit(parseQueryCount(queries)) + .toList(); + } + + @GET("/fortunes") + public ViewRef fortunes(Model model) { + List fortunes = entityManager.find(Fortune.class); + fortunes.add(new Fortune(0, "Additional fortune added at request time.")); + fortunes.sort(Comparator.comparing(Fortune::getMessage)); + + model.addAttribute("fortunes", fortunes); + return ViewRef.forViewName("fortunes"); + } + + @Nullable + private World findWorldById(int id) { + return entityManager.findById(World.class, boxed[id]); + } + + // + + private static IntStream randomNumbers() { + return ThreadLocalRandom.current() + .ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER) + .distinct(); + } + + private static final Integer[] boxed = IntStream.range(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER + 1) + .boxed() + .toArray(Integer[]::new); + + private static Integer nextInt() { + return boxed[ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER)]; + } + + private static int parseQueryCount(@Nullable String textValue) { + if (textValue == null) { + return 1; + } + int parsedValue; + try { + parsedValue = Integer.parseInt(textValue); + } + catch (NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java new file mode 100644 index 00000000000..a261c1434bd --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java @@ -0,0 +1,54 @@ +package cn.taketoday.benchmark.model; + +import java.util.Objects; + +import cn.taketoday.jdbc.persistence.Id; +import cn.taketoday.jdbc.persistence.Table; + +@Table("fortune") +public class Fortune { + + @Id + private Integer id; + + private String message; + + public Fortune() { } + + public Fortune(Integer id, String message) { + this.id = id; + this.message = message; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setMessage(String message) { + this.message = message; + } + + public Integer getId() { + return id; + } + + public String getMessage() { + return message; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Fortune fortune)) + return false; + return Objects.equals(id, fortune.id) + && Objects.equals(message, fortune.message); + } + + @Override + public int hashCode() { + return Objects.hash(id, message); + } + +} diff --git a/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java new file mode 100644 index 00000000000..04c60c8445f --- /dev/null +++ b/frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java @@ -0,0 +1,55 @@ +package cn.taketoday.benchmark.model; + +import java.util.Objects; + +import cn.taketoday.jdbc.persistence.Column; +import cn.taketoday.jdbc.persistence.Id; +import cn.taketoday.jdbc.persistence.Table; + +@Table("world") +public class World { + + @Id + private Integer id; + + @Column("randomNumber") + private Integer randomNumber; + + public World() { } + + public World(Integer id, Integer randomNumber) { + this.id = id; + this.randomNumber = randomNumber; + } + + public Integer getId() { + return id; + } + + public Integer getRandomNumber() { + return randomNumber; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setRandomNumber(Integer randomNumber) { + this.randomNumber = randomNumber; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof World world)) + return false; + return Objects.equals(id, world.id) + && Objects.equals(randomNumber, world.randomNumber); + } + + @Override + public int hashCode() { + return Objects.hash(id, randomNumber); + } +} diff --git a/frameworks/Java/today/src/main/resources/application-dev.yaml b/frameworks/Java/today/src/main/resources/application-dev.yaml new file mode 100644 index 00000000000..07dbdf12fbc --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application-dev.yaml @@ -0,0 +1,9 @@ +datasource: + url: jdbc:mysql://localhost:3306/hello_world?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: root + password: 88888888 + +logging: + level: + root: info + sql: debug \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/application-test.yaml b/frameworks/Java/today/src/main/resources/application-test.yaml new file mode 100644 index 00000000000..e901f8a0476 --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application-test.yaml @@ -0,0 +1,14 @@ +datasource: + url: jdbc:mysql://tfb-database:3306/hello_world?useUnicode=true&characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai + username: benchmarkdbuser + password: benchmarkdbpass + +logging: + level: + root: info + +server: + netty: + acceptor-threads: 4 + worker-threads: 8 + max-connection: 65535 \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/application.yaml b/frameworks/Java/today/src/main/resources/application.yaml new file mode 100644 index 00000000000..650df4454a5 --- /dev/null +++ b/frameworks/Java/today/src/main/resources/application.yaml @@ -0,0 +1,41 @@ +app: + name: benchmark-app + +server: + port: 8080 + +infra: + output: + ansi: + enabled: always + +freemarker: + cache: true + settings: + classic_compatible: true + date_format: yyyy-MM-dd + datetime_format: yyyy-MM-dd HH:mm:ss + default_encoding: UTF-8 + locale: UTF-8 + log_template_exceptions: false + number_format: 0.#### + tag_syntax: auto_detect + template_exception_handler: ignore + template_update_delay: 0 + time_format: HH:mm:ss + url_escaping_charset: UTF-8 + +datasource: + name: 'app-datasource' + type: com.zaxxer.hikari.HikariDataSource + driver-class-name: com.mysql.cj.jdbc.Driver + hikari: + maximum-pool-size: 20 + max-lifetime: 120000 + connection-test-query: 'select 1' + +logging: + level: + root: OFF + pattern: + dateformat: 'yyyy-MM-dd HH:mm:ss.SSS' \ No newline at end of file diff --git a/frameworks/Java/today/src/main/resources/templates/fortunes.ftl b/frameworks/Java/today/src/main/resources/templates/fortunes.ftl new file mode 100644 index 00000000000..0ad737e5dcc --- /dev/null +++ b/frameworks/Java/today/src/main/resources/templates/fortunes.ftl @@ -0,0 +1,21 @@ +<#-- @ftlvariable name="fortunes" type="cn.taketoday.benchmark.model.Fortune[]" --> + + + + Fortunes + + + + + + + + <#list fortunes as fortune> + + + + + +
idmessage
#{fortune.id}${fortune.message?html}
+ + \ No newline at end of file diff --git a/frameworks/Java/today/today.dockerfile b/frameworks/Java/today/today.dockerfile new file mode 100644 index 00000000000..b063749f6b1 --- /dev/null +++ b/frameworks/Java/today/today.dockerfile @@ -0,0 +1,11 @@ +FROM gradle:8.6.0-jdk17 as build +COPY --chown=gradle:gradle . /home/gradle/src +WORKDIR /home/gradle/src +RUN gradle installInfraDist --no-daemon + +FROM openjdk:21 +WORKDIR /today +COPY --from=build /home/gradle/src/build/install/today-infra-app/ ./ + +EXPOSE 8080 +ENTRYPOINT "./bin/today"