Browse Source

Add new framework 'today' (#8815)

* 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
Harry Yang 1 year ago
parent
commit
89d83c084a

+ 9 - 0
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

+ 26 - 0
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

+ 30 - 0
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"
+      }
+    }
+  ]
+}

+ 63 - 0
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"
+  ]
+}

+ 20 - 0
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"

+ 7 - 0
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

+ 15 - 0
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'

+ 70 - 0
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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
+ * @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();
+  }
+
+}

+ 13 - 0
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);
+  }
+
+}

+ 120 - 0
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 <a href="https://github.com/TAKETODAY">Harry Yang</a>
+ * @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<Map<String, String>> 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<World> queries(@Nullable String queries) {
+    return randomNumbers()
+            .mapToObj(this::findWorldById)
+            .limit(parseQueryCount(queries))
+            .toList();
+  }
+
+  @GET("/updates")
+  public List<World> 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<Fortune> 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));
+  }
+
+}

+ 54 - 0
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);
+  }
+
+}

+ 55 - 0
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);
+  }
+}

+ 9 - 0
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

+ 14 - 0
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

+ 41 - 0
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'

+ 21 - 0
frameworks/Java/today/src/main/resources/templates/fortunes.ftl

@@ -0,0 +1,21 @@
+<#-- @ftlvariable name="fortunes" type="cn.taketoday.benchmark.model.Fortune[]" -->
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Fortunes</title>
+</head>
+<body>
+<table>
+  <tr>
+    <th>id</th>
+    <th>message</th>
+  </tr>
+    <#list fortunes as fortune>
+      <tr>
+        <td>#{fortune.id}</td>
+        <td>${fortune.message?html}</td>
+      </tr>
+    </#list>
+</table>
+</body>
+</html>

+ 11 - 0
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"