Przeglądaj źródła

Update ktor and dependencies versions, migrate to postgres (#4026)

* Bump versions for ktor framework

* Migrate Ktor to postgres and code cleanup
Ilya Ryzhenkov 7 lat temu
rodzic
commit
cecdbbbf91

+ 3 - 3
frameworks/Kotlin/ktor/benchmark_config.json

@@ -13,7 +13,7 @@
         "port": 9090,
         "approach": "Realistic",
         "classification": "Micro",
-        "database": "MySQL",
+        "database": "Postgres",
         "framework": "ktor",
         "language": "Kotlin",
         "orm": "Raw",
@@ -36,7 +36,7 @@
         "port": 9090,
         "approach": "Realistic",
         "classification": "Micro",
-        "database": "MySQL",
+        "database": "Postgres",
         "framework": "ktor",
         "language": "Kotlin",
         "orm": "Raw",
@@ -59,7 +59,7 @@
         "port": 9090,
         "approach": "Realistic",
         "classification": "Micro",
-        "database": "MySQL",
+        "database": "Postgres",
         "framework": "ktor",
         "language": "Kotlin",
         "orm": "Raw",

+ 15 - 6
frameworks/Kotlin/ktor/pom.xml

@@ -13,12 +13,13 @@
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <gson.version>2.8.2</gson.version>
-        <hikaricp.version>2.7.8</hikaricp.version>
-        <kotlin.version>1.2.50</kotlin.version>
-        <ktor.version>0.9.3-alpha-4</ktor.version>
+        <gson.version>2.8.5</gson.version>
+        <hikaricp.version>3.2.0</hikaricp.version>
+        <kotlin.version>1.2.60</kotlin.version>
+        <ktor.version>0.9.4</ktor.version>
         <logback.version>1.2.3</logback.version>
-        <mysql-connector.version>5.1.46</mysql-connector.version>
+        <mysql.version>5.1.46</mysql.version>
+        <postgresql.version>42.2.2</postgresql.version>
     </properties>
 
     <dependencies>
@@ -62,11 +63,19 @@
             <artifactId>HikariCP</artifactId>
             <version>${hikaricp.version}</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>${postgresql.version}</version>
+        </dependency>
+
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
-            <version>${mysql-connector.version}</version>
+            <version>${mysql.version}</version>
         </dependency>
+        
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>

+ 55 - 51
frameworks/Kotlin/ktor/src/main/kotlin/org/jetbrains/ktor/benchmarks/Hello.kt

@@ -1,7 +1,6 @@
 package org.jetbrains.ktor.benchmarks
 
 import com.google.gson.*
-import com.mysql.jdbc.*
 import com.zaxxer.hikari.*
 import io.ktor.application.*
 import io.ktor.content.*
@@ -14,8 +13,6 @@ import kotlinx.coroutines.experimental.*
 import kotlinx.coroutines.experimental.scheduling.*
 import kotlinx.html.*
 import java.util.concurrent.*
-import java.util.concurrent.atomic.*
-import javax.sql.*
 
 data class Message(val message: String = "Hello, World!")
 data class World(val id: Int, var randomNumber: Int)
@@ -23,12 +20,11 @@ data class Fortune(val id: Int, var message: String)
 
 fun Application.main() {
     val gson = GsonBuilder().create()
-    val DbRows = 10000
-    val pool by lazy {
-        hikari()
-    }
 
-    val databaseDispatcher by lazy { ExperimentalCoroutineDispatcher().blocking(32) }
+    val dbRows = 10000
+    val poolSize = 48
+    val pool by lazy { HikariDataSource(HikariConfig().apply { configurePostgres(poolSize) }) }
+    val databaseDispatcher by lazy { ExperimentalCoroutineDispatcher().blocking(poolSize) }
 
     install(DefaultHeaders)
 
@@ -40,44 +36,40 @@ fun Application.main() {
         }
 
         get("/json") {
-            val content = TextContent(gson.toJson(Message()), ContentType.Application.Json, HttpStatusCode.OK)
-            call.respond(content)
+            call.respondText(gson.toJson(Message()), ContentType.Application.Json, HttpStatusCode.OK)
         }
 
         get("/db") {
-            val response = withContext(databaseDispatcher) {
-                pool.connection.use { connection ->
-                    val random = ThreadLocalRandom.current()
-                    val queries = call.queries()
-                    val result = mutableListOf<World>()
+            val random = ThreadLocalRandom.current()
+            val queries = call.queries()
+            val result = ArrayList<World>(queries ?: 1)
 
-                    connection.prepareStatement("SELECT * FROM World WHERE id = ?").use { statement ->
+            withContext(databaseDispatcher) {
+                pool.connection.use { connection ->
+                    connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
                         for (i in 1..(queries ?: 1)) {
-                            statement.setInt(1, random.nextInt(DbRows) + 1)
-
+                            statement.setInt(1, random.nextInt(dbRows) + 1)
                             statement.executeQuery().use { rs ->
                                 while (rs.next()) {
-                                    result += World(rs.getInt("id"), rs.getInt("randomNumber"))
+                                    result += World(rs.getInt(1), rs.getInt(2))
                                 }
                             }
                         }
-
-                        TextContent(gson.toJson(when (queries) {
-                            null -> result.single()
-                            else -> result
-                        }), ContentType.Application.Json, HttpStatusCode.OK)
                     }
                 }
             }
 
-            call.respond(response)
+            call.respondText(gson.toJson(when (queries) {
+                null -> result.single()
+                else -> result
+            }), ContentType.Application.Json, HttpStatusCode.OK)
         }
 
         get("/fortunes") {
             val result = mutableListOf<Fortune>()
             withContext(databaseDispatcher) {
                 pool.connection.use { connection ->
-                    connection.prepareStatement("select id, message from fortune").use { statement ->
+                    connection.prepareStatement("SELECT id, message FROM fortune").use { statement ->
                         statement.executeQuery().use { rs ->
                             while (rs.next()) {
                                 result += Fortune(rs.getInt(1), rs.getString(2))
@@ -109,15 +101,15 @@ fun Application.main() {
         }
 
         get("/updates") {
-            val t = withContext(databaseDispatcher) {
-                pool.connection.use { connection ->
-                    val queries = call.queries()
-                    val random = ThreadLocalRandom.current()
-                    val result = mutableListOf<World>()
+            val queries = call.queries()
+            val random = ThreadLocalRandom.current()
+            val result = ArrayList<World>(queries ?: 1)
 
+            withContext(databaseDispatcher) {
+                pool.connection.use { connection ->
                     connection.prepareStatement("SELECT id, randomNumber FROM World WHERE id = ?").use { statement ->
                         for (i in 1..(queries ?: 1)) {
-                            statement.setInt(1, random.nextInt(DbRows) + 1)
+                            statement.setInt(1, random.nextInt(dbRows) + 1)
 
                             statement.executeQuery().use { rs ->
                                 while (rs.next()) {
@@ -128,7 +120,7 @@ fun Application.main() {
 
                     }
 
-                    result.forEach { it.randomNumber = random.nextInt(DbRows) + 1 }
+                    result.forEach { it.randomNumber = random.nextInt(dbRows) + 1 }
 
                     connection.prepareStatement("UPDATE World SET randomNumber = ? WHERE id = ?").use { updateStatement ->
                         for ((id, randomNumber) in result) {
@@ -139,34 +131,46 @@ fun Application.main() {
                         }
                     }
 
-                    TextContent(gson.toJson(when (queries) {
-                        null -> result.single()
-                        else -> result
-                    }), ContentType.Application.Json, HttpStatusCode.OK)
                 }
             }
 
-            call.respond(t)
+            call.respondText(gson.toJson(when (queries) {
+                null -> result.single()
+                else -> result
+            }), ContentType.Application.Json, HttpStatusCode.OK)
         }
     }
 }
 
+fun HikariConfig.configurePostgres(poolSize: Int) {
+    jdbcUrl = "jdbc:postgresql://tfb-database/hello_world?useSSL=false"
+    driverClassName = org.postgresql.Driver::class.java.name
+
+    configureCommon(poolSize)
+}
+
+fun HikariConfig.configureCommon(poolSize: Int) {
+    username = "benchmarkdbuser"
+    password = "benchmarkdbpass"
+    addDataSourceProperty("cacheServerConfiguration", true)
+    addDataSourceProperty("cachePrepStmts", "true")
+    addDataSourceProperty("useUnbufferedInput", "false")
+    addDataSourceProperty("prepStmtCacheSize", "4096")
+    addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
+    connectionTimeout = 10000
+    maximumPoolSize = poolSize
+    minimumIdle = poolSize
+}
+
+fun HikariConfig.configureMySql(poolSize: Int) {
+    jdbcUrl = "jdbc:mysql://tfb-database:3306/hello_world?useSSL=false"
+    driverClassName = com.mysql.jdbc.Driver::class.java.name
+    configureCommon(poolSize)
+}
+
 fun ApplicationCall.queries() = try {
     request.queryParameters["queries"]?.toInt()?.coerceIn(1, 500)
 } catch (nfe: NumberFormatException) {
     1
 }
 
-private fun hikari(): DataSource {
-    val config = HikariConfig()
-    config.jdbcUrl = "jdbc:mysql://tfb-database:3306/hello_world?useSSL=false"
-    config.username = "benchmarkdbuser"
-    config.password = "benchmarkdbpass"
-    config.addDataSourceProperty("cachePrepStmts", "true")
-    config.addDataSourceProperty("prepStmtCacheSize", "250")
-    config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
-    config.driverClassName = Driver::class.java.name
-    config.connectionTimeout = 10000
-    config.maximumPoolSize = 100
-    return HikariDataSource(config)
-}