Skip to content

Commit ad39199

Browse files
committed
Updates and cleanup for Ktor benchmarks
1 parent d512b49 commit ad39199

File tree

33 files changed

+495
-400
lines changed

33 files changed

+495
-400
lines changed

frameworks/Kotlin/ktor/Readme.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
See subprojects
22

33
* [Ktor](ktor/) Ktor using traditional JDBC using various servers
4-
* [Ktor-asyncdb](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients
4+
* [Ktor-jasync](ktor-asyncdb/) Ktor with Netty-based PostgreSQL clients
5+
* [Ktor-r2dbc](ktor-r2dbc/) Ktor with R2DBC for reactive database access
6+
* [Ktor-exposed](ktor-exposed/) Ktor with the Exposed database abstraction library
7+
* [Ktor-pgclient](ktor-pgclient/) Ktor with Reactive PostgreSQL Client

frameworks/Kotlin/ktor/benchmark_config.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@
101101
"query_url": "/query/?queries=",
102102
"fortune_url": "/fortunes",
103103
"update_url": "/updates?queries=",
104-
"port": 8080,
104+
"port": 9090,
105105
"approach": "Realistic",
106106
"classification": "Fullstack",
107107
"database": "Postgres",
@@ -125,7 +125,7 @@
125125
"update_url": "/updates?queries=",
126126
"fortune_url": "/fortunes",
127127

128-
"port": 8080,
128+
"port": 9090,
129129
"approach": "Realistic",
130130
"classification": "Micro",
131131
"database": "Postgres",

frameworks/Kotlin/ktor/ktor-asyncdb/build.gradle.kts

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ repositories {
1313
}
1414

1515
application {
16-
mainClass.set("MainKt")
16+
mainClass = "io.ktor.server.netty.EngineMain"
1717
}
1818

19-
val ktor_version = "2.3.12"
20-
val kotlinx_serialization_version = "1.7.3"
19+
val ktor_version = "3.1.2"
20+
val kotlinx_serialization_version = "1.8.1"
2121

2222
dependencies {
2323
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version")
@@ -26,6 +26,7 @@ dependencies {
2626
implementation("io.ktor:ktor-server-default-headers:$ktor_version")
2727
implementation("io.ktor:ktor-server-html-builder:$ktor_version")
2828
implementation("com.github.jasync-sql:jasync-postgresql:2.2.4")
29+
implementation("ch.qos.logback:logback-classic:1.5.12")
2930
}
3031

3132
java {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import kotlinx.serialization.Serializable
2+
3+
@Serializable
4+
data class Message(val message: String)
5+
6+
@Serializable
7+
data class World(val id: Int, var randomNumber: Int)
8+
9+
@Serializable
10+
data class Fortune(val id: Int, var message: String)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import io.ktor.http.*
2+
import io.ktor.http.content.*
3+
import io.ktor.server.response.*
4+
import io.ktor.server.routing.*
5+
import kotlinx.serialization.json.Json
6+
7+
// Optimized JSON instance with better performance settings
8+
internal val json = Json {
9+
prettyPrint = false
10+
isLenient = true
11+
ignoreUnknownKeys = true
12+
coerceInputValues = true
13+
}
14+
15+
internal suspend inline fun <reified E> RoutingCall.respondJson(response: E) {
16+
respond(TextContent(
17+
json.encodeToString(response),
18+
ContentType.Application.Json
19+
))
20+
}

frameworks/Kotlin/ktor/ktor-asyncdb/src/main/kotlin/main.kt

+32-58
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,16 @@ import com.github.jasync.sql.db.QueryResult
33
import com.github.jasync.sql.db.SuspendingConnection
44
import com.github.jasync.sql.db.asSuspending
55
import com.github.jasync.sql.db.postgresql.PostgreSQLConnectionBuilder
6-
import io.ktor.http.ContentType
76
import io.ktor.server.application.*
8-
import io.ktor.server.engine.embeddedServer
97
import io.ktor.server.html.*
10-
import io.ktor.server.netty.Netty
118
import io.ktor.server.plugins.defaultheaders.*
129
import io.ktor.server.response.*
1310
import io.ktor.server.routing.*
1411
import kotlinx.coroutines.*
1512
import kotlinx.html.*
16-
import kotlinx.serialization.Serializable
17-
import kotlinx.serialization.encodeToString
18-
import kotlinx.serialization.json.Json
19-
import java.lang.IllegalArgumentException
2013
import kotlin.random.Random
2114
import kotlin.random.nextInt
2215

23-
@Serializable
24-
data class Message(val message: String)
25-
26-
@Serializable
27-
data class World(val id: Int, val randomNumber: Int)
28-
29-
data class Fortune(val id: Int, val message: String)
30-
3116
val rand = Random(1)
3217

3318
interface Repository {
@@ -121,57 +106,46 @@ class FortuneTemplate(private val fortunes: List<Fortune>, private val main: Mai
121106
}
122107
}
123108

124-
fun main(args: Array<String>) {
125-
val db = when(args.firstOrNull()) {
126-
"jasync-sql" -> JasyncRepository()
127-
else -> throw IllegalArgumentException("Must specify a postgres client")
128-
}
109+
fun Application.main() {
129110

130-
val server = embeddedServer(Netty, 8080, configure = {
131-
shareWorkGroup = true
132-
}) {
133-
install(DefaultHeaders)
134-
routing {
135-
get("/plaintext") {
136-
call.respondText("Hello, World!")
137-
}
111+
val db = JasyncRepository()
138112

139-
get("/json") {
140-
call.respondText(
141-
Json.encodeToString(Message("Hello, World!")),
142-
ContentType.Application.Json
143-
)
144-
}
113+
install(DefaultHeaders)
114+
routing {
115+
get("/plaintext") {
116+
call.respondText("Hello, World!")
117+
}
145118

146-
get("/db") {
147-
call.respondText(Json.encodeToString(db.getWorld()), ContentType.Application.Json)
148-
}
119+
get("/json") {
120+
call.respondJson(Message("Hello, World!"))
121+
}
149122

150-
get("/query/") {
151-
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
152-
val worlds = (1..queries).map { db.getWorld() }
153-
call.respondText(Json.encodeToString(worlds), ContentType.Application.Json)
154-
}
123+
get("/db") {
124+
call.respondJson(db.getWorld())
125+
}
155126

156-
get("/fortunes") {
157-
val newFortune = Fortune(0, "Additional fortune added at request time.")
158-
val fortunes = db.getFortunes().toMutableList()
159-
fortunes.add(newFortune)
160-
fortunes.sortBy { it.message }
161-
call.respondHtmlTemplate(FortuneTemplate(fortunes)) { }
162-
}
127+
get("/query/") {
128+
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
129+
val worlds = (1..queries).map { db.getWorld() }
130+
call.respondJson(worlds)
131+
}
163132

164-
get("/updates") {
165-
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
166-
val worlds = (1..queries).map { db.getWorld() }
167-
val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) }
133+
get("/fortunes") {
134+
val newFortune = Fortune(0, "Additional fortune added at request time.")
135+
val fortunes = db.getFortunes().toMutableList()
136+
fortunes.add(newFortune)
137+
fortunes.sortBy { it.message }
138+
call.respondHtmlTemplate(FortuneTemplate(fortunes)) { }
139+
}
168140

169-
db.updateWorlds(newWorlds)
141+
get("/updates") {
142+
val queries = call.parameters["queries"]?.toBoxedInt(1..500) ?: 1
143+
val worlds = (1..queries).map { db.getWorld() }
144+
val newWorlds = worlds.map { it.copy(randomNumber = rand.nextInt(1..10000)) }
170145

171-
call.respondText(Json.encodeToString(newWorlds), ContentType.Application.Json)
172-
}
146+
db.updateWorlds(newWorlds)
147+
148+
call.respondJson(newWorlds)
173149
}
174150
}
175-
176-
server.start(wait = true)
177151
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
ktor {
2+
deployment {
3+
port = 9090
4+
autoreload = false
5+
watch = [ ]
6+
shareWorkGroup = true
7+
}
8+
9+
application {
10+
modules = [MainKt.main]
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<configuration>
2+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
3+
<encoder>
4+
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
5+
</encoder>
6+
</appender>
7+
8+
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
9+
<neverBlock>true</neverBlock>
10+
<appender-ref ref="STDOUT" />
11+
</appender>
12+
13+
14+
<root level="INFO">
15+
<appender-ref ref="ASYNC"/>
16+
</root>
17+
18+
<logger name="org.eclipse.jetty" level="INFO"/>
19+
<logger name="io.netty" level="INFO"/>
20+
21+
</configuration>

frameworks/Kotlin/ktor/ktor-exposed/app/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ repositories {
99
mavenCentral()
1010
}
1111

12-
val ktorVersion = "3.1.1"
12+
val ktorVersion = "3.1.2"
1313
val kotlinxSerializationVersion = "1.8.0"
1414
val exposedVersion = "0.59.0"
1515

frameworks/Kotlin/ktor/ktor-exposed/app/src/main/kotlin/App.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import kotlinx.coroutines.Dispatchers
1313
import kotlinx.coroutines.withContext
1414
import kotlinx.html.*
1515
import kotlinx.serialization.Serializable
16-
import kotlinx.serialization.encodeToString
1716
import kotlinx.serialization.json.Json
1817
import org.jetbrains.exposed.dao.IntEntity
1918
import org.jetbrains.exposed.dao.IntEntityClass
@@ -70,7 +69,7 @@ enum class ExposedMode {
7069

7170
fun main(args: Array<String>) {
7271
val exposedMode = valueOf(args.first())
73-
embeddedServer(Netty, port = 8080) { module(exposedMode) }.start(wait = true)
72+
embeddedServer(Netty, port = 9090) { module(exposedMode) }.start(wait = true)
7473
}
7574

7675
fun Application.module(exposedMode: ExposedMode) {

frameworks/Kotlin/ktor/ktor-pgclient.dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@ FROM amazoncorretto:21-al2023-headless
1010
WORKDIR /app
1111
COPY --from=build /app/build/libs/ktor-pgclient.jar ktor-pgclient.jar
1212

13-
EXPOSE 8080
13+
EXPOSE 9090
1414

1515
CMD ["java", "-server","-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AlwaysPreTouch", "-jar", "ktor-pgclient.jar"]

frameworks/Kotlin/ktor/ktor-pgclient/README.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,27 @@ The client features batching, pipelining and supports coroutines.
77

88
### Plain Text Test
99

10-
http://localhost:8080/plaintext
10+
http://localhost:9090/plaintext
1111

1212
### JSON Encoding Test
1313

14-
http://localhost:8080/json
14+
http://localhost:9090/json
1515

1616
### Single Query Test
1717

18-
http://localhost:8080/db
18+
http://localhost:9090/db
1919

2020
### Multiple Queries Test
2121

22-
http://localhost:8080/query?queries=
22+
http://localhost:9090/query?queries=
2323

2424
### Database updates Test
2525

26-
http://localhost:8080/updates?queries=
26+
http://localhost:9090/updates?queries=
2727

2828
### Fortunes Test
2929

30-
http://localhost:8080/fortunes
30+
http://localhost:9090/fortunes
3131

3232
## build
3333

frameworks/Kotlin/ktor/ktor-pgclient/build.gradle.kts

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@ repositories {
1313
}
1414

1515
application {
16-
mainClass.set("MainKt")
16+
mainClass = "io.ktor.server.netty.EngineMain"
1717
}
1818

19-
val ktor_version = "2.3.12"
19+
val ktor_version = "3.1.2"
2020
val vertx_version = "4.5.11"
2121

2222
dependencies {
23-
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3")
23+
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1")
2424
implementation("io.ktor:ktor-server-netty:$ktor_version")
2525
implementation("io.ktor:ktor-server-html-builder-jvm:$ktor_version")
2626
implementation("io.ktor:ktor-server-default-headers-jvm:$ktor_version")
2727
implementation("io.vertx:vertx-pg-client:$vertx_version")
2828
implementation("io.vertx:vertx-lang-kotlin:$vertx_version")
2929
implementation("io.vertx:vertx-lang-kotlin-coroutines:$vertx_version")
30+
implementation("ch.qos.logback:logback-classic:1.5.12")
3031
}
3132

3233
java {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import kotlinx.serialization.Serializable
2+
3+
@Serializable
4+
data class Message(val message: String)
5+
6+
@Serializable
7+
data class World(val id: Int, var randomNumber: Int)
8+
9+
@Serializable
10+
data class Fortune(val id: Int, var message: String)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import io.ktor.http.*
2+
import io.ktor.http.content.*
3+
import io.ktor.server.response.*
4+
import io.ktor.server.routing.*
5+
import kotlinx.serialization.json.Json
6+
7+
// Optimized JSON instance with better performance settings
8+
internal val json = Json {
9+
prettyPrint = false
10+
isLenient = true
11+
ignoreUnknownKeys = true
12+
coerceInputValues = true
13+
}
14+
15+
internal suspend inline fun <reified E> RoutingCall.respondJson(response: E) {
16+
respond(TextContent(
17+
json.encodeToString(response),
18+
ContentType.Application.Json
19+
))
20+
}

0 commit comments

Comments
 (0)