From 7286bd06d2e92f46e0016c9b30ecaef82eb30821 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Mon, 30 Dec 2024 21:17:32 +0700 Subject: [PATCH 1/9] added r2dbc --- frameworks/Kotlin/ktor/benchmark_config.json | 23 +++ .../ktor/ktor-exposed/app/build.gradle.kts | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile | 13 ++ frameworks/Kotlin/ktor/ktor-r2dbc/README.md | 50 ++++++ frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml | 163 +++++++++++++++++ .../src/main/assembly/cio-bundle.xml | 30 ++++ .../src/main/assembly/jetty-bundle.xml | 30 ++++ .../src/main/assembly/netty-bundle.xml | 29 +++ .../org/jetbrains/ktor/benchmarks/Hello.kt | 169 ++++++++++++++++++ .../ktor/benchmarks/models/Fortune.kt | 6 + .../ktor/benchmarks/models/Message.kt | 6 + .../jetbrains/ktor/benchmarks/models/World.kt | 6 + .../src/main/resources/application.conf | 20 +++ .../ktor-r2dbc/src/main/resources/logback.xml | 21 +++ frameworks/Kotlin/ktor/ktor/README.md | 6 +- frameworks/Kotlin/ktor/ktor/pom.xml | 2 +- .../org/jetbrains/ktor/benchmarks/Hello.kt | 2 +- 18 files changed, 573 insertions(+), 7 deletions(-) create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/README.md create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Fortune.kt create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Message.kt create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/World.kt create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml diff --git a/frameworks/Kotlin/ktor/benchmark_config.json b/frameworks/Kotlin/ktor/benchmark_config.json index 3a213a240ba..5a9b1816736 100644 --- a/frameworks/Kotlin/ktor/benchmark_config.json +++ b/frameworks/Kotlin/ktor/benchmark_config.json @@ -25,6 +25,29 @@ "notes": "http://ktor.io/", "versus": "netty" }, + "r2dbc": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "fortune_url": "/fortunes", + + "port": 9090, + "approach": "Realistic", + "classification": "Micro", + "database": "Postgres", + "framework": "ktor", + "language": "Kotlin", + "orm": "Raw", + "platform": "Netty", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "ktor-netty-r2dbc", + "notes": "http://ktor.io/", + "versus": "netty" + }, "jetty": { "plaintext_url": "/plaintext", "json_url": "/json", diff --git a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts index 80a9debfa16..5d6db161d20 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts @@ -9,7 +9,7 @@ repositories { mavenCentral() } -val ktorVersion = "3.0.1" +val ktorVersion = "3.0.3" val kotlinxSerializationVersion = "1.7.3" val exposedVersion = "0.56.0" diff --git a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties index bdc9a83b1e6..4eaec467050 100644 --- a/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-exposed/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile new file mode 100644 index 00000000000..076a51a1416 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile @@ -0,0 +1,13 @@ +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven +WORKDIR /ktor +COPY ktor/pom.xml pom.xml +COPY ktor/src src +RUN mvn clean package -q + +FROM amazoncorretto:21-al2023-headless +WORKDIR /ktor +COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar + +EXPOSE 9090 + +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/README.md b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md new file mode 100644 index 00000000000..5b758d68dbd --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/README.md @@ -0,0 +1,50 @@ +# Ktor + +Ktor is a framework for building servers and clients in connected systems using Kotlin programming language. +More information is available at [ktor.io](http://ktor.io). + +# Setup + +* Java 21 +* Postgres server + +# Requirements + +* Maven 3 +* JDK 21 +* Kotlin +* ktor +* netty +* R2DBC + +Maven is downloaded automatically via Maven Wrapper script (`mvnw`), add dependencies are specified in `pom.xml` so will be downloaded automatically from maven central and jcenter repositories. + +# Deployment + +Run maven to build a bundle + +```bash +./mvnw package +``` + +Once bundle build complete and mysql server is running you can launch the application + +```bash +java -jar target/tech-empower-framework-benchmark-1.0-SNAPSHOT.jar +``` + +Please note that the server holds tty so you may need nohup. See `setup.sh` for details. + +# Contact + +[Leonid Stashevsky](https://github.com/e5l) + +[Sergey Mashkov](https://github.com/cy6erGn0m) + +[Ilya Ryzhenkov](https://github.com/orangy) + +[Ilya Nemtsev](https://github.com/inemtsev) + +Slack ktor channel https://kotlinlang.slack.com/messages/ktor (you need an [invite](http://slack.kotlinlang.org/) to join) + + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml new file mode 100644 index 00000000000..9590236be6c --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml @@ -0,0 +1,163 @@ + + + + 4.0.0 + + org.jetbrains.ktor + tech-empower-framework-benchmark + 1.0-SNAPSHOT + jar + + org.jetbrains.ktor tech-empower-framework-benchmark + + + 2.0.21 + 1.10.1 + 3.0.3 + 1.7.3 + 0.11.0 + UTF-8 + 1.2.13 + 42.7.4 + 1.0.7.RELEASE + + + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-core + ${serialization.version} + + + org.jetbrains.kotlinx + kotlinx-serialization-json + ${serialization.version} + + + org.jetbrains.kotlinx + kotlinx-html-jvm + ${kotlinx.html.version} + + + org.jetbrains.kotlinx + kotlinx-coroutines-core + ${kotlin.coroutines.version} + + + org.jetbrains.kotlinx + kotlinx-coroutines-reactor + ${kotlin.coroutines.version} + + + io.ktor + ktor-server-default-headers-jvm + ${ktor.version} + + + io.ktor + ktor-server-html-builder-jvm + ${ktor.version} + + + + org.postgresql + r2dbc-postgresql + ${r2dbc.version} + + + + ch.qos.logback + logback-classic + ${logback.version} + + + io.ktor + ktor-server-netty-jvm + ${ktor.version} + + + + + src/main/kotlin + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + compile + + + + test-compile + test-compile + + test-compile + + + + + + kotlinx-serialization + + + + + org.jetbrains.kotlin + kotlin-maven-serialization + ${kotlin.version} + + + + + maven-jar-plugin + + true + + + + default-jar + none + + + + + maven-assembly-plugin + 3.0.0 + + + + netty + + single + + + package + + + + src/main/assembly/netty-bundle.xml + + + + io.ktor.server.netty.EngineMain + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml new file mode 100644 index 00000000000..8b515de6096 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml @@ -0,0 +1,30 @@ + + cio-bundle + + jar + + + false + + + + true + runtime + + true + + + *:ktor-server-netty + *:ktor-server-jetty + + + + + + + ${project.build.outputDirectory} + / + + + \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml new file mode 100644 index 00000000000..8b55f09e7ef --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml @@ -0,0 +1,30 @@ + + jetty-bundle + + jar + + + false + + + + true + runtime + + true + + + *:ktor-server-netty + *:ktor-server-cio + + + + + + + ${project.build.outputDirectory} + / + + + \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml new file mode 100644 index 00000000000..58ff7cff593 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/netty-bundle.xml @@ -0,0 +1,29 @@ + + netty-bundle + + + jar + + + false + + + + true + runtime + + + *:ktor-server-jetty + *:ktor-server-cio + + + + + + + ${project.build.outputDirectory} + / + + + \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt new file mode 100644 index 00000000000..bac39bd6a7e --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -0,0 +1,169 @@ +package org.jetbrains.ktor.benchmarks + +import io.ktor.http.* +import io.ktor.http.content.* +import io.ktor.server.application.* +import io.ktor.server.config.* +import io.ktor.server.html.* +import io.ktor.server.plugins.defaultheaders.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import io.r2dbc.spi.ConnectionFactories +import io.r2dbc.spi.ConnectionFactory +import io.r2dbc.spi.ConnectionFactoryOptions +import kotlinx.coroutines.* +import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.html.* +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import org.jetbrains.ktor.benchmarks.Constants.DB_ROWS +import org.jetbrains.ktor.benchmarks.Constants.FORTUNES_QUERY +import org.jetbrains.ktor.benchmarks.Constants.UPDATE_QUERY +import org.jetbrains.ktor.benchmarks.Constants.WORLD_QUERY +import org.jetbrains.ktor.benchmarks.models.Fortune +import org.jetbrains.ktor.benchmarks.models.Message +import org.jetbrains.ktor.benchmarks.models.World +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono +import kotlin.random.Random + +fun Application.main() { + val config = ApplicationConfig("application.conf") + val dbConnFactory = configurePostgresR2DBC(config) + + install(DefaultHeaders) + + val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain) + + routing { + get("/plaintext") { + call.respond(helloWorldContent) + } + + get("/json") { + call.respondText(Json.encodeToString(Message("Hello, world!")), ContentType.Application.Json) + } + + get("/db") { + val random = Random.Default + val request = getWorld(dbConnFactory, random) + val result = request.awaitFirstOrNull() + + call.respondText(Json.encodeToString(result), ContentType.Application.Json) + } + + suspend fun selectWorlds(queries: Int, random: Random): List = coroutineScope { + val result = ArrayList>(queries) + + repeat(queries) { + val deferred = async { + getWorld(dbConnFactory, random).awaitFirstOrNull() + } + result.add(deferred) + } + + result.awaitAll().filterNotNull() + } + + get("/queries") { + val queries = call.queries() + val random = Random.Default + + val result = selectWorlds(queries, random) + + call.respondText(Json.encodeToString(result), ContentType.Application.Json) + } + + get("/fortunes") { + val result = mutableListOf() + + val request = Flux.usingWhen(dbConnFactory.create(), { connection -> + Flux.from(connection.createStatement(FORTUNES_QUERY).execute()).flatMap { r -> + Flux.from(r.map { row, _ -> + Fortune( + row.get(0, Int::class.java)!!, row.get(1, String::class.java)!! + ) + }) + } + }, { connection -> connection.close() }) + + request.collectList().awaitFirstOrNull()?.let { result.addAll(it) } + + result.add(Fortune(0, "Additional fortune added at request time.")) + result.sortBy { it.message } + call.respondHtml { + head { title { +"Fortunes" } } + body { + table { + tr { + th { +"id" } + th { +"message" } + } + for (fortune in result) { + tr { + td { +fortune.id.toString() } + td { +fortune.message } + } + } + } + } + } + } + + get("/updates") { + val queries = call.queries() + val random = Random.Default + + val result = coroutineScope { + val worlds = selectWorlds(queries, random) + + worlds.forEach { it.randomNumber = random.nextInt(DB_ROWS) + 1 } + + val updateRequests = worlds.map { world -> + Mono.usingWhen(dbConnFactory.create(), { connection -> + Mono.from( + connection.createStatement(UPDATE_QUERY).bind(0, world.randomNumber).bind(1, world.id) + .execute() + ).flatMap { Mono.from(it.rowsUpdated) } + }, { connection -> connection.close() }) + } + + Flux.merge(updateRequests).collectList().awaitFirstOrNull() + worlds + } + + call.respondText(Json.encodeToString(result), ContentType.Application.Json) + } + } +} + +private fun getWorld( + dbConnFactory: ConnectionFactory, random: Random +): Mono = Mono.usingWhen(dbConnFactory.create(), { connection -> + Mono.from(connection.createStatement(WORLD_QUERY).bind(0, random.nextInt(DB_ROWS) + 1).execute()).flatMap { r -> + Mono.from(r.map { row, _ -> + World( + row.get(0, Int::class.java)!!, row.get(1, Int::class.java)!! + ) + }) + } +}, { connection -> connection.close() }) + +private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory { + val options = ConnectionFactoryOptions.builder().option(ConnectionFactoryOptions.DRIVER, "database.driver") + .option(ConnectionFactoryOptions.DATABASE, config.property("database.url").getString()) + .option(ConnectionFactoryOptions.USER, config.property("database.user").getString()) + .option(ConnectionFactoryOptions.PASSWORD, config.property("database.password").getString()).build() + + return ConnectionFactories.get(options) +} + +private fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 + + +object Constants { + const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?" + const val FORTUNES_QUERY = "SELECT id, message FROM fortune" + const val UPDATE_QUERY = "UPDATE World SET randomNumber = ? WHERE id = ?" + const val DB_ROWS = 10000 +} diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Fortune.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Fortune.kt new file mode 100644 index 00000000000..40b75ef4354 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Fortune.kt @@ -0,0 +1,6 @@ +package org.jetbrains.ktor.benchmarks.models + +import kotlinx.serialization.Serializable + +@Serializable +class Fortune(val id: Int, var message: String) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Message.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Message.kt new file mode 100644 index 00000000000..fc9bd1fada1 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/Message.kt @@ -0,0 +1,6 @@ +package org.jetbrains.ktor.benchmarks.models + +import kotlinx.serialization.Serializable + +@Serializable +class Message(val message: String) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/World.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/World.kt new file mode 100644 index 00000000000..0c35be5c969 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/models/World.kt @@ -0,0 +1,6 @@ +package org.jetbrains.ktor.benchmarks.models + +import kotlinx.serialization.Serializable + +@Serializable +class World(val id: Int, var randomNumber: Int) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf new file mode 100644 index 00000000000..a253814ac55 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf @@ -0,0 +1,20 @@ +ktor { + deployment { + port = 9090 + autoreload = false + watch = [ ] + shareWorkGroup = true + } + + application { + modules = [ org.jetbrains.ktor.benchmarks.HelloKt.main ] + } +} + +database { + driver = "org.postgresql.Driver" + url = "url: r2dbc:pool://tfb-database:5432/hello_world?loggerLevel=OFF&sslmode=disable" + poolsize = 512 + username = "benchmarkdbuser" + password = "benchmarkdbpass" +} diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml new file mode 100644 index 00000000000..9fd0f518971 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/logback.xml @@ -0,0 +1,21 @@ + + + + %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + true + + + + + + + + + + + + diff --git a/frameworks/Kotlin/ktor/ktor/README.md b/frameworks/Kotlin/ktor/ktor/README.md index e3c141a70e0..31f2755e24c 100644 --- a/frameworks/Kotlin/ktor/ktor/README.md +++ b/frameworks/Kotlin/ktor/ktor/README.md @@ -5,13 +5,13 @@ More information is available at [ktor.io](http://ktor.io). # Setup -* Java 17 -* MySQL server +* Java 21 +* Postgres server # Requirements * Maven 3 -* JDK 17 +* JDK 21 * Kotlin * ktor * netty diff --git a/frameworks/Kotlin/ktor/ktor/pom.xml b/frameworks/Kotlin/ktor/ktor/pom.xml index 74d725ca6fa..670b77cdf51 100644 --- a/frameworks/Kotlin/ktor/ktor/pom.xml +++ b/frameworks/Kotlin/ktor/ktor/pom.xml @@ -13,7 +13,7 @@ 2.0.21 - 3.0.2 + 3.0.3 1.7.3 0.11.0 UTF-8 diff --git a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index b44808fba40..a83a16f326b 100644 --- a/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -38,7 +38,7 @@ fun Application.main() { install(DefaultHeaders) - val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain).also { it.contentLength } + val helloWorldContent = TextContent("Hello, World!", ContentType.Text.Plain) routing { get("/plaintext") { From 83abea6d2a0df54f3c46cf5e16ab9d9971d8fc75 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Tue, 31 Dec 2024 03:06:39 +0700 Subject: [PATCH 2/9] fixed test and some perf bugs --- frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile | 10 +- frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml | 17 ++- .../org/jetbrains/ktor/benchmarks/Hello.kt | 45 +++++-- .../NioClientEventLoopResources.java | 123 ++++++++++++++++++ .../src/main/resources/application.conf | 14 +- 5 files changed, 187 insertions(+), 22 deletions(-) create mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile index 076a51a1416..9281f4974ac 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-r2dbc.dockerfile @@ -1,12 +1,12 @@ FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven -WORKDIR /ktor -COPY ktor/pom.xml pom.xml -COPY ktor/src src +WORKDIR /ktor-r2dbc +COPY ktor-r2dbc/pom.xml pom.xml +COPY ktor-r2dbc/src src RUN mvn clean package -q FROM amazoncorretto:21-al2023-headless -WORKDIR /ktor -COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar +WORKDIR /ktor-r2dbc +COPY --from=maven /ktor-r2dbc/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-netty-bundle.jar app.jar EXPOSE 9090 diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml index 9590236be6c..092e8ab9559 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/pom.xml @@ -18,9 +18,12 @@ 1.7.3 0.11.0 UTF-8 - 1.2.13 + 1.5.12 + 3.7.1 42.7.4 1.0.7.RELEASE + 1.0.2.RELEASE + @@ -64,13 +67,21 @@ ktor-server-html-builder-jvm ${ktor.version} - org.postgresql r2dbc-postgresql ${r2dbc.version} - + + io.r2dbc + r2dbc-pool + ${r2dbc.pool.version} + + + io.projectreactor + reactor-core + ${reactor.version} + ch.qos.logback logback-classic diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index bac39bd6a7e..053e2d90ea0 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -8,6 +8,14 @@ import io.ktor.server.html.* import io.ktor.server.plugins.defaultheaders.* import io.ktor.server.response.* import io.ktor.server.routing.* +import io.r2dbc.pool.ConnectionPool +import io.r2dbc.pool.ConnectionPoolConfiguration +import io.r2dbc.pool.PoolingConnectionFactoryProvider +import io.r2dbc.postgresql.PostgresqlConnectionConfiguration +import io.r2dbc.postgresql.PostgresqlConnectionFactory +import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider +import io.r2dbc.postgresql.client.SSLMode +import io.r2dbc.spi.Connection import io.r2dbc.spi.ConnectionFactories import io.r2dbc.spi.ConnectionFactory import io.r2dbc.spi.ConnectionFactoryOptions @@ -25,6 +33,8 @@ import org.jetbrains.ktor.benchmarks.models.Message import org.jetbrains.ktor.benchmarks.models.World import reactor.core.publisher.Flux import reactor.core.publisher.Mono +import reactor.netty.resources.LoopResources +import java.time.Duration import kotlin.random.Random fun Application.main() { @@ -125,7 +135,7 @@ fun Application.main() { connection.createStatement(UPDATE_QUERY).bind(0, world.randomNumber).bind(1, world.id) .execute() ).flatMap { Mono.from(it.rowsUpdated) } - }, { connection -> connection.close() }) + }, Connection::close) } Flux.merge(updateRequests).collectList().awaitFirstOrNull() @@ -147,23 +157,38 @@ private fun getWorld( ) }) } -}, { connection -> connection.close() }) +}, Connection::close) private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory { - val options = ConnectionFactoryOptions.builder().option(ConnectionFactoryOptions.DRIVER, "database.driver") - .option(ConnectionFactoryOptions.DATABASE, config.property("database.url").getString()) - .option(ConnectionFactoryOptions.USER, config.property("database.user").getString()) - .option(ConnectionFactoryOptions.PASSWORD, config.property("database.password").getString()).build() - - return ConnectionFactories.get(options) + val cfo = PostgresqlConnectionConfiguration.builder() + .host(config.property("db.host").getString()) + .port(config.property("db.port").getString().toInt()) + .database(config.property("db.database").getString()) + .username(config.property("db.username").getString()) + .password(config.property("db.password").getString()) + .loopResources { NioClientEventLoopResources(Runtime.getRuntime().availableProcessors()).cacheLoops() } + .sslMode(SSLMode.DISABLE) + .tcpKeepAlive(true) + .tcpNoDelay(true) + .build() + + val cf = PostgresqlConnectionFactory(cfo) + + val cp = ConnectionPoolConfiguration.builder(cf) + .initialSize(config.property("db.initPoolSize").getString().toInt()) + .maxSize(config.property("db.maxPoolSize").getString().toInt()) + //.maxLifeTime(Duration.ofMillis(Long.MAX_VALUE)) + .build() + + return ConnectionPool(cp) } private fun ApplicationCall.queries() = request.queryParameters["queries"]?.toIntOrNull()?.coerceIn(1, 500) ?: 1 object Constants { - const val WORLD_QUERY = "SELECT id, randomNumber FROM World WHERE id = ?" + const val WORLD_QUERY = "SELECT id, randomnumber FROM world WHERE id = $1" const val FORTUNES_QUERY = "SELECT id, message FROM fortune" - const val UPDATE_QUERY = "UPDATE World SET randomNumber = ? WHERE id = ?" + const val UPDATE_QUERY = "UPDATE world SET randomnumber = $1 WHERE id = $2" const val DB_ROWS = 10000 } diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java new file mode 100644 index 00000000000..d0e03bb6b5e --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/NioClientEventLoopResources.java @@ -0,0 +1,123 @@ +package org.jetbrains.ktor.benchmarks; + +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.DatagramChannel; +import io.netty.channel.socket.ServerSocketChannel; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioDatagramChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.util.concurrent.DefaultThreadFactory; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.ThreadPerTaskExecutor; +import reactor.core.publisher.Mono; +import reactor.netty.FutureMono; +import reactor.netty.resources.LoopResources; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Copied from GitHub issue comment: https://github.com/r2dbc/r2dbc-pool/issues/190#issuecomment-1566845190 + */ +public class NioClientEventLoopResources implements LoopResources { + public static final String THREAD_PREFIX = "prefix-"; + final int threads; + final AtomicReference loops = new AtomicReference<>(); + final AtomicBoolean running; + + NioClientEventLoopResources(int threads) { + this.running = new AtomicBoolean(true); + this.threads = threads; + } + + + @Override + @SuppressWarnings("unchecked") + public Mono disposeLater(Duration quietPeriod, Duration timeout) { + return Mono.defer(() -> { + long quietPeriodMillis = quietPeriod.toMillis(); + long timeoutMillis = timeout.toMillis(); + EventLoopGroup serverLoopsGroup = loops.get(); + Mono slMono = Mono.empty(); + if (running.compareAndSet(true, false)) { + if (serverLoopsGroup != null) { + slMono = FutureMono.from((Future) serverLoopsGroup.shutdownGracefully( + quietPeriodMillis, timeoutMillis, TimeUnit.MILLISECONDS)); + } + } + return Mono.when(slMono); + }); + } + + @Override + public boolean isDisposed() { + return !running.get(); + } + + @Override + public EventLoopGroup onClient(boolean useNative) { + return cacheLoops(); + } + + @Override + public EventLoopGroup onServer(boolean useNative) { + throw new UnsupportedOperationException("This event loop is designed only for client DB calls."); + } + + @Override + public EventLoopGroup onServerSelect(boolean useNative) { + throw new UnsupportedOperationException("This event loop is designed only for client DB calls."); + } + + @Override + public CHANNEL onChannel(Class channelType, EventLoopGroup group) { + if (channelType.equals(SocketChannel.class)) { + return (CHANNEL) new NioSocketChannel(); + } + if (channelType.equals(ServerSocketChannel.class)) { + return (CHANNEL) new NioServerSocketChannel(); + } + if (channelType.equals(DatagramChannel.class)) { + return (CHANNEL) new NioDatagramChannel(); + } + throw new IllegalArgumentException("Unsupported channel type: " + channelType.getSimpleName()); + } + + @Override + public Class onChannelClass(Class channelType, + EventLoopGroup group) { + if (channelType.equals(SocketChannel.class)) { + return (Class) NioSocketChannel.class; + } + if (channelType.equals(ServerSocketChannel.class)) { + return (Class) NioServerSocketChannel.class; + } + if (channelType.equals(DatagramChannel.class)) { + return (Class) NioDatagramChannel.class; + } + throw new IllegalArgumentException("Unsupported channel type: " + channelType.getSimpleName()); + } + + @SuppressWarnings("FutureReturnValueIgnored") + EventLoopGroup cacheLoops() { + EventLoopGroup eventLoopGroup = loops.get(); + if (null == eventLoopGroup) { + EventLoopGroup newEventLoopGroup = createNewEventLoopGroup(); + if (!loops.compareAndSet(null, newEventLoopGroup)) { + //"FutureReturnValueIgnored" this is deliberate + newEventLoopGroup.shutdownGracefully(0, 0, TimeUnit.MILLISECONDS); + } + eventLoopGroup = cacheLoops(); + } + return eventLoopGroup; + } + + private NioEventLoopGroup createNewEventLoopGroup() { + return new NioEventLoopGroup(threads, new ThreadPerTaskExecutor(new DefaultThreadFactory(THREAD_PREFIX))); + } +} \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf index a253814ac55..fe2031a7699 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/resources/application.conf @@ -11,10 +11,16 @@ ktor { } } -database { - driver = "org.postgresql.Driver" - url = "url: r2dbc:pool://tfb-database:5432/hello_world?loggerLevel=OFF&sslmode=disable" - poolsize = 512 +db { + driver = "pool" + protocol = "postgresql" + ssl = "false" + host = "tfb-database" + port = 5432 + database = "hello_world" + initPoolSize = 512 + maxPoolSize = 512 username = "benchmarkdbuser" password = "benchmarkdbpass" + //url = "r2dbc:postgresql://"${db.host}":"${db.port}"/"${db.database}"?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=16&sslmode=disable&maxSize="${db.poolSize} } From 15a1faac30332d36ab48cd94e8278613d412a116 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Tue, 31 Dec 2024 03:42:14 +0700 Subject: [PATCH 3/9] improved updated/queries via Flows --- .../org/jetbrains/ktor/benchmarks/Hello.kt | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index 053e2d90ea0..1715b0c643c 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -20,6 +20,9 @@ import io.r2dbc.spi.ConnectionFactories import io.r2dbc.spi.ConnectionFactory import io.r2dbc.spi.ConnectionFactoryOptions import kotlinx.coroutines.* +import kotlinx.coroutines.flow.* +import kotlinx.coroutines.reactive.asFlow +import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.html.* import kotlinx.serialization.encodeToString @@ -62,24 +65,21 @@ fun Application.main() { call.respondText(Json.encodeToString(result), ContentType.Application.Json) } - suspend fun selectWorlds(queries: Int, random: Random): List = coroutineScope { - val result = ArrayList>(queries) - + fun selectWorlds(queries: Int, random: Random): Flow = flow { repeat(queries) { - val deferred = async { - getWorld(dbConnFactory, random).awaitFirstOrNull() - } - result.add(deferred) + emit(getWorld(dbConnFactory, random).awaitFirst()) } - - result.awaitAll().filterNotNull() } get("/queries") { val queries = call.queries() val random = Random.Default - val result = selectWorlds(queries, random) + val result = buildList { + selectWorlds(queries, random).collect { + add(it) + } + } call.respondText(Json.encodeToString(result), ContentType.Application.Json) } @@ -127,9 +127,14 @@ fun Application.main() { val result = coroutineScope { val worlds = selectWorlds(queries, random) - worlds.forEach { it.randomNumber = random.nextInt(DB_ROWS) + 1 } + val worldsUpdated = buildList { + worlds.collect { + it.randomNumber = random.nextInt(DB_ROWS) + 1 + add(it) + } + } - val updateRequests = worlds.map { world -> + val updateRequests = worldsUpdated.map { world -> Mono.usingWhen(dbConnFactory.create(), { connection -> Mono.from( connection.createStatement(UPDATE_QUERY).bind(0, world.randomNumber).bind(1, world.id) @@ -138,8 +143,8 @@ fun Application.main() { }, Connection::close) } - Flux.merge(updateRequests).collectList().awaitFirstOrNull() - worlds + Flux.merge(updateRequests).collectList().awaitFirst() + worldsUpdated } call.respondText(Json.encodeToString(result), ContentType.Application.Json) From 3cc613cebd28c78eab929df8429d169a407e498d Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Wed, 1 Jan 2025 16:23:07 +0700 Subject: [PATCH 4/9] some refactor --- .../org/jetbrains/ktor/benchmarks/Hello.kt | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index 1715b0c643c..9dbef8bbd3b 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -124,30 +124,25 @@ fun Application.main() { val queries = call.queries() val random = Random.Default - val result = coroutineScope { - val worlds = selectWorlds(queries, random) + val worlds = selectWorlds(queries, random) - val worldsUpdated = buildList { - worlds.collect { - it.randomNumber = random.nextInt(DB_ROWS) + 1 - add(it) - } - } + val worldsUpdated = buildList { + worlds.collect { world -> + world.randomNumber = random.nextInt(DB_ROWS) + 1 + add(world) - val updateRequests = worldsUpdated.map { world -> Mono.usingWhen(dbConnFactory.create(), { connection -> Mono.from( - connection.createStatement(UPDATE_QUERY).bind(0, world.randomNumber).bind(1, world.id) + connection.createStatement(UPDATE_QUERY) + .bind(0, world.randomNumber) + .bind(1, world.id) .execute() ).flatMap { Mono.from(it.rowsUpdated) } - }, Connection::close) + }, Connection::close).awaitFirstOrNull() } - - Flux.merge(updateRequests).collectList().awaitFirst() - worldsUpdated } - call.respondText(Json.encodeToString(result), ContentType.Application.Json) + call.respondText(Json.encodeToString(worldsUpdated), ContentType.Application.Json) } } } @@ -182,7 +177,6 @@ private fun configurePostgresR2DBC(config: ApplicationConfig): ConnectionFactory val cp = ConnectionPoolConfiguration.builder(cf) .initialSize(config.property("db.initPoolSize").getString().toInt()) .maxSize(config.property("db.maxPoolSize").getString().toInt()) - //.maxLifeTime(Duration.ofMillis(Long.MAX_VALUE)) .build() return ConnectionPool(cp) From fd62a31476793f50894bdf95d8fae6a99cf0b799 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Wed, 1 Jan 2025 18:25:27 +0700 Subject: [PATCH 5/9] update jvm to be version 21 across all Ktor versions for consistency --- frameworks/Kotlin/ktor/ktor-cio.dockerfile | 4 +-- frameworks/Kotlin/ktor/ktor-jetty.dockerfile | 4 +-- .../src/main/assembly/cio-bundle.xml | 30 ------------------- .../src/main/assembly/jetty-bundle.xml | 30 ------------------- 4 files changed, 4 insertions(+), 64 deletions(-) delete mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml delete mode 100644 frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index 33059ec9fd4..07f8c268f64 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.9.7-amazoncorretto-17-debian as maven +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM amazoncorretto:17.0.11-al2023-headless +FROM amazoncorretto:21-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio-bundle.jar app.jar diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index e753d7cc442..08e13edc189 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -1,10 +1,10 @@ -FROM maven:3.9.7-amazoncorretto-17-debian as maven +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /ktor COPY ktor/pom.xml pom.xml COPY ktor/src src RUN mvn clean package -q -FROM amazoncorretto:17.0.11-al2023-headless +FROM amazoncorretto:21-al2023-headless WORKDIR /ktor COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jetty-bundle.jar app.jar diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml deleted file mode 100644 index 8b515de6096..00000000000 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/cio-bundle.xml +++ /dev/null @@ -1,30 +0,0 @@ - - cio-bundle - - jar - - - false - - - - true - runtime - - true - - - *:ktor-server-netty - *:ktor-server-jetty - - - - - - - ${project.build.outputDirectory} - / - - - \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml deleted file mode 100644 index 8b55f09e7ef..00000000000 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/assembly/jetty-bundle.xml +++ /dev/null @@ -1,30 +0,0 @@ - - jetty-bundle - - jar - - - false - - - - true - runtime - - true - - - *:ktor-server-netty - *:ktor-server-cio - - - - - - - ${project.build.outputDirectory} - / - - - \ No newline at end of file From 61970eb87036c37792542ef42c06c19d4a5c3217 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Wed, 1 Jan 2025 18:35:01 +0700 Subject: [PATCH 6/9] update jvm settings to be same for all ktor tests --- frameworks/Kotlin/ktor/ktor-cio.dockerfile | 2 +- frameworks/Kotlin/ktor/ktor-jetty.dockerfile | 2 +- .../kotlin/org/jetbrains/ktor/benchmarks/Hello.kt | 11 ++--------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-cio.dockerfile b/frameworks/Kotlin/ktor/ktor-cio.dockerfile index 07f8c268f64..7443aed952f 100644 --- a/frameworks/Kotlin/ktor/ktor-cio.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-cio.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-cio EXPOSE 9090 -CMD ["java", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile index 08e13edc189..52855ab4a55 100644 --- a/frameworks/Kotlin/ktor/ktor-jetty.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jetty.dockerfile @@ -10,4 +10,4 @@ COPY --from=maven /ktor/target/tech-empower-framework-benchmark-1.0-SNAPSHOT-jet EXPOSE 9090 -CMD ["java", "-jar", "app.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "app.jar"] diff --git a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt index 9dbef8bbd3b..461c6e303e8 100644 --- a/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt +++ b/frameworks/Kotlin/ktor/ktor-r2dbc/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt @@ -10,18 +10,13 @@ import io.ktor.server.response.* import io.ktor.server.routing.* import io.r2dbc.pool.ConnectionPool import io.r2dbc.pool.ConnectionPoolConfiguration -import io.r2dbc.pool.PoolingConnectionFactoryProvider import io.r2dbc.postgresql.PostgresqlConnectionConfiguration import io.r2dbc.postgresql.PostgresqlConnectionFactory -import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider import io.r2dbc.postgresql.client.SSLMode import io.r2dbc.spi.Connection -import io.r2dbc.spi.ConnectionFactories import io.r2dbc.spi.ConnectionFactory -import io.r2dbc.spi.ConnectionFactoryOptions -import kotlinx.coroutines.* -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.reactive.asFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.reactive.awaitFirst import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.html.* @@ -36,8 +31,6 @@ import org.jetbrains.ktor.benchmarks.models.Message import org.jetbrains.ktor.benchmarks.models.World import reactor.core.publisher.Flux import reactor.core.publisher.Mono -import reactor.netty.resources.LoopResources -import java.time.Duration import kotlin.random.Random fun Application.main() { From 1f9313599eef7251b59212bea34b25da459a4dec Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Wed, 1 Jan 2025 18:49:53 +0700 Subject: [PATCH 7/9] updated old docker files --- frameworks/Kotlin/ktor/ktor-jasync.dockerfile | 4 ++-- frameworks/Kotlin/ktor/ktor-pgclient.dockerfile | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index 8c66e81ea4e..32c273fa129 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.7-amazoncorretto-17-debian +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven WORKDIR /app COPY ktor-asyncdb/gradle gradle COPY ktor-asyncdb/build.gradle.kts build.gradle.kts @@ -10,4 +10,4 @@ RUN /app/gradlew --no-daemon shadowJar EXPOSE 9090 -CMD ["java", "-server", "-XX:+UseParallelGC", "-Xms2G","-Xmx2G", "-jar", "/app/build/libs/bench.jar", "jasync-sql"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "/app/build/libs/bench.jar", "jasync-sql"] diff --git a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile index 0cf012e7596..58f087f6bc8 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.7-amazoncorretto-17-debian as build +FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as build WORKDIR /app COPY ktor-pgclient/gradle gradle COPY ktor-pgclient/build.gradle.kts build.gradle.kts @@ -6,10 +6,10 @@ COPY ktor-pgclient/gradlew gradlew COPY ktor-pgclient/src src RUN /app/gradlew --no-daemon shadowJar -FROM amazoncorretto:17.0.11-al2023-headless +FROM amazoncorretto:21-al2023-headless WORKDIR /app COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar EXPOSE 8080 -CMD ["java", "-server", "-XX:MaxRAMFraction=1", "-XX:-UseBiasedLocking", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"] +CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"] From 724f7a4b3ee90c7ccf3732cfb2d35e6a8d590b31 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Thu, 2 Jan 2025 16:30:18 +0700 Subject: [PATCH 8/9] fixed pgclient test --- .../gradle/wrapper/gradle-wrapper.properties | 2 +- frameworks/Kotlin/ktor/ktor-jasync.dockerfile | 15 ++++++--------- frameworks/Kotlin/ktor/ktor-pgclient.dockerfile | 2 +- .../Kotlin/ktor/ktor-pgclient/build.gradle.kts | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties index 3d66c176054..aae61b4adc9 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index 32c273fa129..8bda3725d0d 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -1,13 +1,10 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as maven -WORKDIR /app -COPY ktor-asyncdb/gradle gradle -COPY ktor-asyncdb/build.gradle.kts build.gradle.kts -COPY ktor-asyncdb/gradle.properties gradle.properties -COPY ktor-asyncdb/gradlew gradlew +FROM gradle:jdk21 + +WORKDIR /ktor-asyncdb COPY ktor-asyncdb/settings.gradle settings.gradle -COPY ktor-asyncdb/src src -RUN /app/gradlew --no-daemon shadowJar +COPY ktor-asyncdb/app app +RUN gradle --no-daemon shadowJar EXPOSE 9090 -CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "/app/build/libs/bench.jar", "jasync-sql"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "/app/build/libs/bench.jar", "jasync-sql"] diff --git a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile index 58f087f6bc8..301f5e55c31 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-pgclient.dockerfile @@ -1,4 +1,4 @@ -FROM maven:3.9.9-amazoncorretto-21-debian-bookworm as build +FROM gradle:jdk21 as build WORKDIR /app COPY ktor-pgclient/gradle gradle COPY ktor-pgclient/build.gradle.kts build.gradle.kts diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts index f080b64d69f..a9c2a02417a 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts @@ -29,7 +29,7 @@ dependencies { } tasks.withType().configureEach { - kotlinOptions.jvmTarget = "17" + kotlinOptions.jvmTarget = "21" } tasks.shadowJar { diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties index e1bef7e873c..81aa1c0448a 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-pgclient/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 981a75bd698c76627755cb5397f41042a3c75e91 Mon Sep 17 00:00:00 2001 From: Ilya Nemtsev Date: Fri, 3 Jan 2025 11:35:42 +0700 Subject: [PATCH 9/9] fixed older variants --- .../Kotlin/ktor/ktor-asyncdb/build.gradle.kts | 15 ++++++++++----- .../Kotlin/ktor/ktor-asyncdb/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 1 - .../Kotlin/ktor/ktor-asyncdb/settings.gradle | 14 -------------- .../ktor/ktor-asyncdb/settings.gradle.kts | 1 + frameworks/Kotlin/ktor/ktor-jasync.dockerfile | 17 +++++++++++------ .../Kotlin/ktor/ktor-pgclient/build.gradle.kts | 17 ++++++++++------- 7 files changed, 33 insertions(+), 34 deletions(-) delete mode 100644 frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle create mode 100644 frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts index 61cedf013ce..029a0973171 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts @@ -1,6 +1,6 @@ plugins { application - kotlin("jvm") version "1.9.22" + kotlin("jvm") version "2.0.21" kotlin("plugin.serialization") version "2.0.0" id("com.github.johnrengelman.shadow") version "8.1.0" } @@ -17,8 +17,7 @@ application { } val ktor_version = "2.3.12" -val kotlinx_serialization_version = "1.6.3" -val vertx_pg_client = "4.5.8" +val kotlinx_serialization_version = "1.7.3" dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version") @@ -26,11 +25,17 @@ dependencies { implementation("io.ktor:ktor-server-netty:$ktor_version") implementation("io.ktor:ktor-server-default-headers:$ktor_version") implementation("io.ktor:ktor-server-html-builder:$ktor_version") - implementation("com.github.jasync-sql:jasync-postgresql:2.2.0") + implementation("com.github.jasync-sql:jasync-postgresql:2.2.4") +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } tasks.shadowJar { - archiveBaseName.set("bench") + archiveBaseName.set("ktor-asyncdb") archiveClassifier.set("") archiveVersion.set("") } diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties index 5790d58ceda..9408f64fb4d 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official -kotlin_version=1.9.22 +kotlin_version=2.0.21 ktor_version=2.3.12 diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties index aae61b4adc9..c6a2952d3c1 100644 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,3 @@ -#Fri Dec 07 21:01:17 MST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle deleted file mode 100644 index d58b02872bf..00000000000 --- a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle +++ /dev/null @@ -1,14 +0,0 @@ -pluginManagement { - resolutionStrategy { - eachPlugin { - if (requested.id.id == "org.jetbrains.kotlin.jvm") { - useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") - } - if (requested.id.id == "kotlinx-serialization") { - useModule("org.jetbrains.kotlin:kotlin-serialization:$kotlin_version") - } - } - } -} - -rootProject.name = 'tech-empower-framework-benchmark' \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts new file mode 100644 index 00000000000..fd565dc83c5 --- /dev/null +++ b/frameworks/Kotlin/ktor/ktor-asyncdb/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "tech-empower-framework-benchmark" \ No newline at end of file diff --git a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile index 8bda3725d0d..be5f6dd4606 100644 --- a/frameworks/Kotlin/ktor/ktor-jasync.dockerfile +++ b/frameworks/Kotlin/ktor/ktor-jasync.dockerfile @@ -1,10 +1,15 @@ -FROM gradle:jdk21 +FROM gradle:jdk21 as build +WORKDIR /app +COPY ktor-asyncdb/gradle gradle +COPY ktor-asyncdb/build.gradle.kts build.gradle.kts +COPY ktor-asyncdb/gradlew gradlew +COPY ktor-asyncdb/src src +RUN /app/gradlew --no-daemon shadowJar -WORKDIR /ktor-asyncdb -COPY ktor-asyncdb/settings.gradle settings.gradle -COPY ktor-asyncdb/app app -RUN gradle --no-daemon shadowJar +FROM amazoncorretto:21-al2023-headless +WORKDIR /app +COPY --from=build /app/build/libs/ktor-asyncdb.jar ktor-asyncdb.jar EXPOSE 9090 -CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "/app/build/libs/bench.jar", "jasync-sql"] +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-asyncdb.jar", "jasync-sql"] diff --git a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts index a9c2a02417a..60524844558 100644 --- a/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts +++ b/frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts @@ -1,6 +1,6 @@ plugins { application - kotlin("jvm") version "1.9.22" + kotlin("jvm") version "2.0.21" kotlin("plugin.serialization") version "2.0.0" id("com.github.johnrengelman.shadow") version "8.1.0" } @@ -17,19 +17,22 @@ application { } val ktor_version = "2.3.12" +val vertx_version = "4.5.11" dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") implementation("io.ktor:ktor-server-netty:$ktor_version") implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version") implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version") - implementation("io.vertx:vertx-pg-client:4.5.8") - implementation("io.vertx:vertx-lang-kotlin:4.5.8") - implementation("io.vertx:vertx-lang-kotlin-coroutines:4.5.8") + implementation("io.vertx:vertx-pg-client:$vertx_version") + implementation("io.vertx:vertx-lang-kotlin:$vertx_version") + implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertx_version") } -tasks.withType().configureEach { - kotlinOptions.jvmTarget = "21" +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } } tasks.shadowJar {