🐈
Benchmark Jackson and Protobuf
検証内容について
Protobufがどの程度高速なのかを Java Json Serialize/Deserialize の デファクトスタンダードである Jackson と比較をして確認してみる
Benchmark Program
- build.gradle.kts
version の指定は parent project にて実施しているため、以下の設定の中にはversion情報がない
plugins {
id("me.champeau.jmh")
id("com.google.protobuf")
}
dependencies {
implementation("com.google.protobuf:protobuf-java")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.openjdk.jmh:jmh-generator-annprocess")
}
- message.proto
syntax = "proto3";
message SampleMessage {
string name = 1;
int32 age = 2;
}
- SerializerBenchmark
@State(Scope.Benchmark)
@Fork(1)
@Warmup(iterations = 5) //
@Measurement(iterations = 10) // CNT
open class SerializerBenchmark {
data class SampleJsonMessage(
val name: String,
val age: Long,
)
private val messageBuf = Sample.SampleMessage.newBuilder().setName("John").setAge(25).build()
private val messageJson = SampleJsonMessage(name = "John", age = 25)
private val objectMapper = ObjectMapper().registerModule(
KotlinModule.Builder().build(),
)
@Benchmark
fun protobufSerialize(): ByteArray {
return messageBuf.toByteArray()
}
@Benchmark
fun protobufDeserialize() {
Sample.SampleMessage.parseFrom(messageBuf.toByteArray())
}
@Benchmark
fun jsonSerialize(): String {
return objectMapper.writeValueAsString(messageJson)
}
@Benchmark
fun jsonDeserialize() {
objectMapper.readValue(objectMapper.writeValueAsString(messageJson), SampleJsonMessage::class.java)
}
}
Benchmark Result
Benchmark Mode Cnt Score Error Units
SerializerBenchmark.jsonDeserialize thrpt 10 1413727.543 ± 525960.912 ops/s
SerializerBenchmark.jsonSerialize thrpt 10 6571743.362 ± 1307144.645 ops/s
SerializerBenchmark.protobufDeserialize thrpt 10 18834307.366 ± 3637475.851 ops/s
SerializerBenchmark.protobufSerialize thrpt 10 41709114.574 ± 1426671.240 ops/s
Protobuf vs JSON:
- Protobuf Serialize は、Jackson Serialize よりも約6.3倍高速
- Protobuf Deserialize は、Jackson Deserialize よりも約13.3倍高速
Summary
- Protobufは、serialize/deserialize の両方で Jackson よりも高速
- 特に、大量のデータを高速に処理する必要がある場合や、ネットワーク帯域を節約したい場合には、Protobufを使用することが推奨される
- しかし、可読性やデバッグの容易さを優先する場合は、JSON を使用することが適している
エラーマージン:
- エラーマージンも考慮すると、Protobufのパフォーマンスは一貫して高いが、特に Deserialize のエラーマージンが大きいので、ベンチマークの環境や条件によっては変動があるかも
Etc
- FlatBuffers は protobuf と比べても、より速いようなので、検証してみること
- エラーマージンについて
- ベンチマークの実行中に得られた結果の変動や不確実性を示すもの
- 具体的には、同じ条件でベンチマークを複数回実行した場合、その結果がどれほど一貫しているか(または変動しているか)を示す指標
- ベンチマークの実行中に得られた結果の変動や不確実性を示すもの
Discussion
JSONとProtobufの処理コスト差を比較することが主目的だと思いますが、であればライブラリの選定が適切でないように見えます。
google.protobufはコード生成を用いているのに対し、Jacksonはリフレクションベースのため、その時点で性能差は大きいです。
比較対象にするなら、同じくコード生成を用いるmoshiやkotlinx.serializationの方が適切に見えます。
利用したことは有りませんが、kotlinx.serializationはJSONとProtobuf両方に対応しているようなので、そちらを用いた方がよりフェアな比較になるのではないかと感じました。
コメントありがとうございます。
こちらはおっしゃる通りになります。
今回現場で利用しているlibraryがjacksonであったため選定したという理由でした。
コード生成のアプローチをしているライブラリでも試してみたいと思います!