Browse Source

Add cached query tests (#9680)

* 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

* :art: .gitignore

* :art: 优化构建

* :sparkles: 更新框架,新增 cached_query_url

* :art: 优化使用方式

* :art: 优化使用方式

* :art:

* :art:

* :art: 修改 cached queries 地址
海子 Yang 5 months ago
parent
commit
b73a8a2f8e

+ 2 - 1
frameworks/Java/today/.gitignore

@@ -6,4 +6,5 @@ build
 
 .idea
 today.properties
-gradle
+gradle
+gradlew

+ 4 - 0
frameworks/Java/today/README.md

@@ -17,6 +17,10 @@ http://localhost:8080/db
 
 http://localhost:8080/queries?queries=
 
+### Caching QUERY
+
+http://localhost:8080/cached-queries?count=10
+
 ### UPDATE
 
 http://localhost:8080/update?queries=

+ 2 - 1
frameworks/Java/today/benchmark_config.json

@@ -9,6 +9,7 @@
         "query_url": "/queries?queries=",
         "fortune_url": "/fortunes",
         "update_url": "/updates?queries=",
+        "cached_query_url": "/cached-queries?count=",
         "port": 8080,
         "approach": "Realistic",
         "classification": "Fullstack",
@@ -21,7 +22,7 @@
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "Today",
+        "display_name": "TODAY",
         "notes": "",
         "versus": "None"
       }

+ 18 - 10
frameworks/Java/today/build.gradle

@@ -1,16 +1,16 @@
 description = "benchmark"
 
-apply plugin: "java"
-apply plugin: "application"
-apply plugin: 'cn.taketoday.application'
-apply plugin: 'io.spring.dependency-management'
+apply plugin: 'java'
+apply plugin: 'application'
+apply plugin: 'infra.application'
 
 configure(allprojects) {
   group = "cn.taketoday.benchmark"
 
   repositories {
+    mavenLocal()
     mavenCentral()
-    maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
+    maven { url = "https://oss.sonatype.org/content/repositories/snapshots/" }
   }
 }
 
@@ -24,6 +24,7 @@ dependencies {
   implementation 'mysql:mysql-connector-java'
 
   implementation 'ch.qos.logback:logback-classic'
+  implementation 'com.github.ben-manes.caffeine:caffeine'
 
   implementation('io.netty:netty-transport-native-epoll') {
     artifact {
@@ -31,6 +32,12 @@ dependencies {
     }
   }
 
+  implementation('io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final') {
+    artifact {
+      classifier = 'linux-x86_64'
+    }
+  }
+
 //  implementation('io.netty:netty-transport-native-kqueue') {
 //    artifact {
 //      classifier = 'osx-aarch_64'
@@ -40,23 +47,24 @@ dependencies {
 }
 
 java {
-  sourceCompatibility = JavaVersion.VERSION_17
-  targetCompatibility = JavaVersion.VERSION_17
+  sourceCompatibility = JavaVersion.VERSION_21
+  targetCompatibility = JavaVersion.VERSION_21
 }
 
 application {
   mainClass = 'cn.taketoday.benchmark.BenchmarkApplication'
   applicationDefaultJvmArgs = [
       "-server",
+      "-Xms2G",
+      "-Xmx2G",
       "-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",
+      "-Dio.netty.iouring.iosqeAsyncThreshold=32000",
+      "-Djava.lang.Integer.IntegerCache.high=10000",
       "--add-opens=java.base/java.nio=ALL-UNNAMED",
       "--add-opens=java.base/sun.nio.ch=ALL-UNNAMED"
   ]

+ 1 - 0
frameworks/Java/today/config.toml

@@ -8,6 +8,7 @@ urls.db = "/db"
 urls.query = "/queries?queries="
 urls.update = "/updates?queries="
 urls.fortune = "/fortunes"
+urls.cached_query = "/cached-queries?count="
 approach = "Realistic"
 classification = "Fullstack"
 database = "mysql"

+ 3 - 3
frameworks/Java/today/gradle.properties

@@ -1,6 +1,6 @@
-version=1.0.0
-#infraVersion=4.0.0-Draft.6-SNAPSHOT
-infraVersion=4.0.0-Draft.6
+version=1.1.0
+#infraVersion=5.0-Draft.2
+infraVersion=5.0-Draft.2-SNAPSHOT
 
 org.gradle.caching=true
 org.gradle.jvmargs=-Xmx2048m

+ 43 - 20
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/AppConfig.java

@@ -4,21 +4,26 @@ 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 infra.beans.factory.annotation.DisableAllDependencyInjection;
+import infra.beans.factory.config.BeanDefinition;
+import infra.context.annotation.Configuration;
+import infra.context.annotation.Role;
+import infra.jdbc.RepositoryManager;
+import infra.persistence.EntityManager;
+import infra.stereotype.Component;
+import infra.web.server.WebServerFactoryCustomizer;
+import infra.web.server.error.SendErrorHandler;
+import infra.web.server.support.NettyRequestConfig;
+import infra.web.server.support.NettyWebServerFactory;
+import io.netty.handler.codec.http.DefaultHttpHeaders;
 import io.netty.handler.codec.http.HttpHeaders;
 import io.netty.handler.codec.http.HttpHeadersFactory;
 import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
+import io.netty.incubator.channel.uring.IOUring;
+import io.netty.incubator.channel.uring.IOUringEventLoopGroup;
+import io.netty.incubator.channel.uring.IOUringServerSocketChannel;
 
-import static cn.taketoday.http.HttpHeaders.DATE_FORMATTER;
+import static infra.http.HttpHeaders.DATE_FORMATTER;
 
 /**
  * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
@@ -29,30 +34,41 @@ import static cn.taketoday.http.HttpHeaders.DATE_FORMATTER;
 @Configuration(proxyBeanMethods = false)
 class AppConfig {
 
-  private static final DefaultHttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory();
-
   @Component
-  static RepositoryManager repositoryManager(DataSource dataSource) {
+  public static RepositoryManager repositoryManager(DataSource dataSource) {
     return new RepositoryManager(dataSource);
   }
 
   @Component
-  static EntityManager entityManager(RepositoryManager repositoryManager) {
+  public static EntityManager entityManager(RepositoryManager repositoryManager) {
     return repositoryManager.getEntityManager();
   }
 
+  @Component
+  public static WebServerFactoryCustomizer<NettyWebServerFactory> factoryWebServerFactoryCustomizer() {
+    return factory -> {
+      if (IOUring.isAvailable()) {
+        IOUringEventLoopGroup loopGroup = new IOUringEventLoopGroup();
+        factory.setAcceptorGroup(loopGroup);
+        factory.setWorkerGroup(loopGroup);
+        factory.setSocketChannel(IOUringServerSocketChannel.class);
+      }
+    };
+  }
+
   @Component
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
-  static NettyRequestConfig nettyRequestConfig(SendErrorHandler sendErrorHandler) {
+  public static NettyRequestConfig nettyRequestConfig(SendErrorHandler sendErrorHandler) {
     var factory = new DefaultHttpDataFactory(false);
-    return NettyRequestConfig.forBuilder()
+
+    return NettyRequestConfig.forBuilder(false)
             .httpDataFactory(factory)
             .sendErrorHandler(sendErrorHandler)
             .headersFactory(new HttpHeadersFactory() {
 
               @Override
               public HttpHeaders newHeaders() {
-                HttpHeaders headers = headersFactory.newHeaders();
+                HttpHeaders headers = new ResponseHeaders();
                 headers.set("Server", "TODAY");
                 headers.set("Date", DATE_FORMATTER.format(ZonedDateTime.now()));
                 return headers;
@@ -60,11 +76,18 @@ class AppConfig {
 
               @Override
               public HttpHeaders newEmptyHeaders() {
-                return headersFactory.newEmptyHeaders();
+                return new ResponseHeaders();
               }
             })
-            .secure(false)
             .build();
   }
 
+  static class ResponseHeaders extends DefaultHttpHeaders {
+
+    public ResponseHeaders() {
+      super(name -> { }, v -> { });
+    }
+
+  }
+
 }

+ 2 - 2
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/BenchmarkApplication.java

@@ -1,7 +1,7 @@
 package cn.taketoday.benchmark;
 
-import cn.taketoday.framework.Application;
-import cn.taketoday.framework.InfraApplication;
+import infra.app.Application;
+import infra.app.InfraApplication;
 
 @InfraApplication
 public class BenchmarkApplication {

+ 39 - 32
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/BenchmarkHttpHandler.java

@@ -2,21 +2,21 @@ 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.Message;
 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;
+import infra.http.MediaType;
+import infra.http.ResponseEntity;
+import infra.lang.Nullable;
+import infra.persistence.EntityManager;
+import infra.ui.Model;
+import infra.util.concurrent.Future;
+import infra.web.annotation.GET;
+import infra.web.annotation.RestController;
+import infra.web.view.ViewRef;
 
 /**
  * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
@@ -26,19 +26,23 @@ import cn.taketoday.web.view.ViewRef;
 final class BenchmarkHttpHandler {
 
   private static final int MIN_WORLD_NUMBER = 1;
+
   private static final int MAX_WORLD_NUMBER = 10_000;
 
   private final EntityManager entityManager;
 
+  private final WorldCache worldCache;
+
   BenchmarkHttpHandler(EntityManager entityManager) {
     this.entityManager = entityManager;
+    this.worldCache = new WorldCache(entityManager.find(World.class));
   }
 
   @GET("/json")
-  public ResponseEntity<Map<String, String>> json() {
+  public ResponseEntity<Message> json() {
     return ResponseEntity.ok()
             .contentType(MediaType.APPLICATION_JSON)
-            .body(Map.of("message", "Hello, World!"));
+            .body(new Message("Hello, World!"));
   }
 
   @GET("/plaintext")
@@ -46,30 +50,33 @@ final class BenchmarkHttpHandler {
     return "Hello, World!";
   }
 
+  @Nullable
   @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();
+  public Future<List<World>> queries(@Nullable String queries) {
+    return Future.combine(randomNumbers().limit(parseQueryCount(queries)).mapToObj(this::findWorldByIdFuture))
+            .asList();
+  }
+
+  @GET("/cached-queries")
+  public List<World> cachedQueries(@Nullable String count) {
+    return worldCache.getCachedWorld(parseQueryCount(count));
   }
 
   @GET("/updates")
-  public List<World> updates(@Nullable String queries) {
-    return randomNumbers()
-            .mapToObj(this::findWorldById)
-            .filter(Objects::nonNull)
-            .peek(world -> {
+  public Future<List<World>> updates(@Nullable String queries) {
+    return Future.combine(randomNumbers()
+            .limit(parseQueryCount(queries))
+            .mapToObj(this::findWorldByIdFuture)
+            .map(worldFuture -> worldFuture.map(world -> {
               world.setRandomNumber(nextInt());
               entityManager.updateById(world);
-            })
-            .limit(parseQueryCount(queries))
-            .toList();
+              return world;
+            }))).asList();
   }
 
   @GET("/fortunes")
@@ -82,9 +89,13 @@ final class BenchmarkHttpHandler {
     return ViewRef.forViewName("fortunes");
   }
 
+  private Future<World> findWorldByIdFuture(int id) {
+    return Future.run(() -> findWorldById(id));
+  }
+
   @Nullable
   private World findWorldById(int id) {
-    return entityManager.findById(World.class, boxed[id]);
+    return entityManager.findById(World.class, id);
   }
 
   //
@@ -95,12 +106,8 @@ final class BenchmarkHttpHandler {
             .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 nextInt() {
+    return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER);
   }
 
   private static int parseQueryCount(@Nullable String textValue) {

+ 28 - 0
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/WorldCache.java

@@ -0,0 +1,28 @@
+package cn.taketoday.benchmark.http;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+import cn.taketoday.benchmark.model.World;
+
+public class WorldCache {
+
+  private final World[] cache;
+
+  public WorldCache(List<World> worlds) {
+    this.cache = worlds.toArray(new World[0]);
+  }
+
+  public List<World> getCachedWorld(int count) {
+    World[] worlds = this.cache;
+    int length = worlds.length;
+    ArrayList<World> ret = new ArrayList<>(count);
+    ThreadLocalRandom current = ThreadLocalRandom.current();
+    for (int i = 0; i < count; i++) {
+      ret.add(worlds[current.nextInt(length - 1)]);
+    }
+    return ret;
+  }
+
+}

+ 6 - 0
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/http/package-info.java

@@ -0,0 +1,6 @@
+@NonNullApi
+@NonNullFields
+package cn.taketoday.benchmark.http;
+
+import infra.lang.NonNullApi;
+import infra.lang.NonNullFields;

+ 4 - 3
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Fortune.java

@@ -2,8 +2,8 @@ package cn.taketoday.benchmark.model;
 
 import java.util.Objects;
 
-import cn.taketoday.jdbc.persistence.Id;
-import cn.taketoday.jdbc.persistence.Table;
+import infra.persistence.Id;
+import infra.persistence.Table;
 
 @Table("fortune")
 public class Fortune {
@@ -13,7 +13,8 @@ public class Fortune {
 
   private String message;
 
-  public Fortune() { }
+  public Fortune() {
+  }
 
   public Fortune(Integer id, String message) {
     this.id = id;

+ 14 - 0
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/Message.java

@@ -0,0 +1,14 @@
+package cn.taketoday.benchmark.model;
+
+public class Message {
+
+  private final String message;
+
+  public Message(String message) {
+    this.message = message;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+}

+ 12 - 5
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/World.java

@@ -2,12 +2,12 @@ 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;
+import infra.persistence.Column;
+import infra.persistence.Id;
+import infra.persistence.Table;
 
 @Table("world")
-public class World {
+public class World implements Comparable<World> {
 
   @Id
   private Integer id;
@@ -15,7 +15,8 @@ public class World {
   @Column("randomNumber")
   private Integer randomNumber;
 
-  public World() { }
+  public World() {
+  }
 
   public World(Integer id, Integer randomNumber) {
     this.id = id;
@@ -52,4 +53,10 @@ public class World {
   public int hashCode() {
     return Objects.hash(id, randomNumber);
   }
+
+  @Override
+  public int compareTo(World o) {
+    return Integer.compare(id, o.id);
+  }
+
 }

+ 6 - 0
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/model/package-info.java

@@ -0,0 +1,6 @@
+@NonNullApi
+@NonNullFields
+package cn.taketoday.benchmark.model;
+
+import infra.lang.NonNullApi;
+import infra.lang.NonNullFields;

+ 6 - 0
frameworks/Java/today/src/main/java/cn/taketoday/benchmark/package-info.java

@@ -0,0 +1,6 @@
+@NonNullApi
+@NonNullFields
+package cn.taketoday.benchmark;
+
+import infra.lang.NonNullApi;
+import infra.lang.NonNullFields;

+ 5 - 4
frameworks/Java/today/src/main/resources/application-test.yaml

@@ -5,10 +5,11 @@ datasource:
 
 logging:
   level:
-    root: info
+    root: OFF
 
 server:
   netty:
-    acceptor-threads: 4
-    worker-threads: 8
-    max-connection: 65535
+    acceptor-threads: 8
+    worker-threads: 16
+    max-connection: 8192
+    validate-headers: false

+ 2 - 5
frameworks/Java/today/src/main/resources/application.yaml

@@ -30,12 +30,9 @@ datasource:
   type: com.zaxxer.hikari.HikariDataSource
   driver-class-name: com.mysql.cj.jdbc.Driver
   hikari:
-    maximum-pool-size: 20
-    max-lifetime: 120000
+    maximum-pool-size: 256
     connection-test-query: 'select 1'
 
 logging:
   level:
-    root: OFF
-  pattern:
-    dateformat: 'yyyy-MM-dd HH:mm:ss.SSS'
+    root: OFF

+ 8 - 6
frameworks/Java/today/today.dockerfile

@@ -1,11 +1,13 @@
-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 gradle:8.13.0-jdk21 as build
+COPY --chown=gradle:gradle . /infra-src
+WORKDIR /infra-src
+RUN gradle installDist --no-daemon
 
-FROM openjdk:21
+#FROM openjdk:21
+FROM bellsoft/liberica-openjre-debian:21.0.5
+RUN apt install findutils
 WORKDIR /today
-COPY --from=build /home/gradle/src/build/install/today-infra-app/ ./
+COPY --from=build /infra-src/build/install/today/ ./
 
 EXPOSE 8080
 ENTRYPOINT "./bin/today"