Upgrade to Pro — share decks privately, control downloads, hide ads and more …

なんとなくgRPC-Java を使ってるそこの俺、gRPC-Kotlin に移行したらどうだ?

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

なんとなくgRPC-Java を使ってるそこの俺、gRPC-Kotlin に移行したらどうだ?

Avatar for Ryo Sakaguchi

Ryo Sakaguchi

April 08, 2026

More Decks by Ryo Sakaguchi

Other Decks in Programming

Transcript

  1. Copyright © Henry, Inc. All rights reserved. なんとなくgRPC-Java を使っ てるそこの俺、gRPC-Kotlin

    に移行したらどうだ? 株式会社ヘンリー: 坂口 諒 (wakwak3125) gRPC-Java vs gRPC-Kotlin
  2. Copyright © Henry, Inc. All rights reserved. • 2020年くらいまで Android

    アプリ開発社 • ヘンリーには副業でバックエンドエンジニアと して参画しその後入社 ◦ ヘンリーでやってること ▪ 医療機関向けの導入効率化 ▪ いろんな外部システムとの連携 • 電子処方箋連携 • 検体検査とか • 趣味はゲームとかギターとか ◦ FF14, VALORANT • 3年前くらいからお父さんしています • 技術書典20の原稿を落とした犯人です。これ で前科二犯 自己紹介 坂口諒(わくわく) wakwak3125 / wakwakjp
  3. Copyright © Henry, Inc. All rights reserved. 技術書典20 新刊出ます 電子カルテの開発を支える技術4

    ~ モダンな技術で再発明する ~ • レセコンチーム通信 Vol.1 • 電子カルテとレセプトコン ピュータの標準仕様 • 電子カルテと部門システムの連 携:その稼働を支えるサポート • 開発を支える振り返りプロセス の変遷 • 本番運用中のアプリーケーショ ンにおけるデータマイグレー ションの難しさ • 医薬品のコードと計算の世界へ ようこそ!
  4. Copyright © Henry, Inc. All rights reserved. • Henryはサーバー間通信にgRPCを採用している •

    gRPC-Kotlinが登場してたかしてないか位の時期だった ◦ → そのまま特に困ってないのでgRPC-Javaをそのまま使い続けている • リリースから時間も経っているしもしかしたら移行するとメリットがあるか も? ◦ → 登壇あるし調べてみるか!という背景 背景
  5. Copyright © Henry, Inc. All rights reserved. • パート1 gRPC-Kotlinとは何か

    • パート2 書き味はどうか • パート3 キャンセルまわりの地味な安心感 • パート4 移行コストとリスク • パート5 パフォーマンスと結論 今日話すこと
  6. Copyright © Henry, Inc. All rights reserved. • 変わるのは サービス実装(RPCハンドラ)

    と クライアントスタブ だけ • サーバー設定・Interceptor等のインフラ層はgRPC-Java APIがそのまま残 る • サービス実装がCoroutineベース(suspend function / Flow)に • MessageビルダーにDSL構文が使える gRPC-KotlinはgRPC-Javaのラッパー
  7. Copyright © Henry, Inc. All rights reserved. 何が変わるか gRPC-Java gRPC-Kotlin

    サーバー実装 StreamObserver suspend function クライアント BlockingStub CoroutineStub Streaming StreamObserver Flow サーバー設定 gRPC-Java API 変更なし Interceptor gRPC-Java API 変更なし
  8. Copyright © Henry, Inc. All rights reserved. • 書き味はKotlinらしく:StreamObserverのコールバック →

    suspend funの return / throw • エラーハンドリングが自然なKotlinコードに • サーバー間通信の一連の処理がすべてsuspend functionで書ける • とはいえ、乗り換えるぞ!の気持ちにはならん • → 構造的なメリットとして全部suspend funになる、というところが大きい ここまでのまとめ
  9. Copyright © Henry, Inc. All rights reserved. • CoroutineScope →

    RPCハンドラ(suspend fun) → 下流サービス呼び出し (suspend fun) → ... • 全部suspend funなので、親子関係がCoroutineScopeで繋がる ◦ → スコープをキャンセル = 子も孫も全部止まる • 普通に書けばキャンセル伝播が良い感じになる suspend funで統一されると何が起きるか
  10. Copyright © Henry, Inc. All rights reserved. • Client →

    Server A → Server B → Server C • Server B に意図的な遅延(Kotlin: delay() / Java: Thread.sleep()) • Client が1秒でタイムアウト → キャンセル発生 • Server C にリクエストが到達するか? 検証:キャンセル伝播
  11. Copyright © Henry, Inc. All rights reserved. → 差はクライアント側ではなく サーバー側のリソース浪費。高負荷時に積み重

    なるとスレッドプール枯渇につながる(この辺は設定次第) キャンセル伝播:結果比較 gRPC-Kotlin gRPC-Java クライアント応答 1秒(同じ) 1秒(同じ) Server Bのリソース解放 即座 delay完走まで占有 Server Cへの呼び出し 未発生 未発生
  12. Copyright © Henry, Inc. All rights reserved. • この検証は delay()

    vs Thread.sleep() という制御された環境でのデモ • JDBCのようなブロッキングI/Oでは、Kotlin側でもキャンセルに即応しない • ただし: RPCハンドラの入口・出口でのキャンセルは確実に機能する • suspend-nativeなI/Oライブラリ(R2DBC、Ktor Client等)では即座に キャンセル ◦ → 差は「構造的にキャンセルが保証される設計かどうか」にある 検証の前提と限界
  13. Copyright © Henry, Inc. All rights reserved. • Client →

    Server A → Server B → Server C • それぞれのgRPCスタブ呼び出しは すべてsuspend fun • キャンセルが効かないのはJDBC等の 末端のDB呼び出し部分 ◦ 呼び出しチェーンが深いほど、キャンセル伝播が効く区間の方が多い → キャンセル周りの挙動はCoroutineが今のところ良さそうな感じ 呼び出しチェーンが深いほど効く
  14. Copyright © Henry, Inc. All rights reserved. 直列チェーン • 入力チェック

    → 料金計算 → 決済処理 → 明細発行 • 途中でキャンセル → 残りのホップは実行されない 並列呼び出し • coroutineScope + async で複数サービスを並列呼び出し • クライアントがキャンセル → 全部即キャンセル • 1つがエラー → 他も自動キャンセル(Structured Concurrency) キャンセル伝播が効くパターン
  15. Copyright © Henry, Inc. All rights reserved. • Java 21+

    で StructuredTaskScope がPreviewとして存在 • 1つ失敗で他を自動キャンセル(coroutineScopeと同じ感じ) • Java 26(2026年3月)時点でも6th Preview(正式化されていない) • gRPC-JavaはStructuredTaskScopeと(たぶん)統合されていない ◦ → 正式化+gRPC-Java対応で差は縮まるポイント Java側のStructured Concurrency
  16. Copyright © Henry, Inc. All rights reserved. • Graceful Shutdownの実装はJava/Kotlin共通:

    server.shutdown() → 完 了待ち → タイムアウトで shutdownNow() • gRPC-Kotlinでは shutdownNow() だけでCoroutineもキャンセルされる (検証済み) • 理由: gRPC-Kotlinが各RPCの ServerCall.Listener.onCancel() で rpcJob.cancel() を呼んでいる ◦ → gRPC callキャンセル → Coroutineキャンセルが自動連鎖する仕組み • scope.cancel() の別途呼び出しは不要 シャットダウン時のキャンセル
  17. Copyright © Henry, Inc. All rights reserved. • JDBC中心のCRUDサービスでは 体感できる差は小さい

    • Javaでも deadline を適切に設定すれば、gRPC層のキャンセルはちゃんと機 能する じゃあ価値は • ミスを減らす — Context.isCancelled() を明示的に書かなくていい • ファンアウト — 並列呼び出しの失敗伝播が自然に書ける • 障害時のセーフティネット — 下流が詰まった時にリソースを漏らしにくい → 派手に効くというより「普通に書いても安全」な設計としての価値 正直なところ
  18. Copyright © Henry, Inc. All rights reserved. • gRPC-Kotlinのメリットは キャンセル伝播の構造的な安心感

    • 劇的に速くなったり障害が減ったりするわけではないが、書き手がミスしに くくくなる • シャットダウンの実装はJava/Kotlin共通(shutdownNowでCoroutineも自 動キャンセル) • Java側もStructuredTaskScopeで追いつきつつあるが、gRPC-Javaとの統 合はまだ ここまでのまとめ
  19. Copyright © Henry, Inc. All rights reserved. → suspend /

    Flow への根本的な書き換え Streaming書き換えコスト:Server Streaming(中) 観点 gRPC-Java gRPC-Kotlin メソッド void m(Req, StreamObserver<Res>) fun m(Req): Flow<Res> 送信 observer.onNext() emit() 完了 observer.onCompleted() Flow終了で自動
  20. Copyright © Henry, Inc. All rights reserved. → コールバック →

    suspend / Flow への根本的な書き換え Streaming書き換えコスト:Bidirectional Streaming(大) 観点 gRPC-Java gRPC-Kotlin メソッド StreamObserver<Req> m(StreamObserver<Res>) fun m(Flow<Req>): Flow<Res> 受信 onNext(req) コールバック requests.collect {} 状態管理 StreamObserverのフィールド Flow内のローカル変数
  21. Copyright © Henry, Inc. All rights reserved. • Interceptor設定はgRPC-Java APIをそのまま使う

    → 既存Interceptorはそ のまま動作 • Coroutineのスレッド切り替え時も gRPC Context (io.grpc.Context) は 正しく伝播 • GrpcContextElement が自動的にattach/detach • スレッドが変わっても gRPC Context の値は維持される Interceptor互換性
  22. Copyright © Henry, Inc. All rights reserved. • サービス間通信: Kotlin↔Java間は完全互換(ワイヤプロトコルが同一)

    • 同一プロセス内: Java実装とKotlin実装を共存登録して正常動作 • → サービス単位でも、同一プロセス内でも段階的に移行できる • → 新規サービスだけKotlinで書き始める、という選択肢も安全 段階的移行
  23. Copyright © Henry, Inc. All rights reserved. • 最新版: v1.5.0(2025年9月)

    • gRPC-Java依存: 内部はgRPC-Java 1.62.2(より新しいバージョンでも動 作) • gRPC-Java最新: v1.80.0(2026年3月)→ 差が開きつつある • 最終コミット: 2025年12月(2026年はコミットなし) • メンテナンスはされてるけど、最新までは追いついていない gRPC-Kotlinのメンテナンス状況
  24. Copyright © Henry, Inc. All rights reserved. 指標 Kotlin Java

    倍率 p50 18.66ms 5.18ms 3.6x p95 88.04ms 12.58ms 7.0x p99 335ms 38.32ms 8.8x RPS 308 1,100 3.6x 1,000 req / 10並列 / delay=0 / A→B→Cチェーン → 一見Javaが3.6倍速い。JVMウォームアップ不足の影響 パフォーマンス:ウォームアップなし
  25. Copyright © Henry, Inc. All rights reserved. 2,000 reqウォームアップ後、10,000 req

    / 10並列 → ウォームアップ後はほぼ同等。Slowest の差は1サンプル差レベルなので参考 程度 パフォーマンス:ウォームアップあり 指標 Kotlin Java 倍率 p50 2.32ms 1.89ms 1.2x p95 3.91ms 3.93ms ≒同等 p99 6.08ms 7.98ms ≒同等 RPS 3,800 4,211 1.1x Slowest 13.92ms 39.62ms —
  26. Copyright © Henry, Inc. All rights reserved. • Coroutineオーバーヘッド:+0.4ms /

    3ホップ(1ホップあたり+0.14ms) • プロダクションのI/O待ち(数ms〜数百ms)に対して誤差 • 注意: ウォームアップ前は差が誇張される • テイルレイテンシに差があるように見えるが、今回の条件(並列 10・delay=0・1回計測)では 測定誤差の可能性が高い。再現性は未検証 • → パフォーマンスは移行判断の障壁にならない パフォーマンス分析
  27. Copyright © Henry, Inc. All rights reserved. • Unary中心のサービス —

    書き換えコストが低い • 呼び出しチェーンが深い — キャンセル伝播の構造的な安心感が活きる • Coroutineを既に活用 — 学習コストなし、既存コードとシームレスに統合 • 新規サービスの立ち上げ — 移行コストゼロ 判断軸:乗り換えを推奨
  28. Copyright © Henry, Inc. All rights reserved. 急がなくてよい • Streaming多用

    — Bidirectional Streamingの書き換えはパラダイムが変わ る • gRPC-Java部分で困っていない — 呼び出しが浅く、キャンセル管理が単純 • 劇的に改善する部分は少ない(ユースケース次第) 判断軸:急がなくてよい / 慎重に判断
  29. Copyright © Henry, Inc. All rights reserved. • gRPC-Kotlinは gRPC-Javaのラッパー

    → 段階的に移行できる • 特に印象的だったのは キャンセル伝播の構造的な安心感 • パフォーマンスは ウォームアップ後ほぼ同等 • 移行コストをペイしておつりが来るか を自分のプロダクトで判断する 最後に
  30. Copyright © Henry, Inc. All rights reserved. 採用情報や事業や技術について、積極的に発信しています! 採用情報 採用募集ページ

    募集中の採用ポジションや募集要項 がご確認いただけます。 オープンポジションのカジュアル面 談も募集していますので、お気軽に お申し込みください。 技術ブログ はてなブログ ヘンリー製品開発チームが運営する 技術ブログです。 会社公式ブログ note ヘンリーで働く人や医療業界や事業 のことが幅広くしれる公式ブログで す。 CEO の逆瀬川も個人で NOTE を発 信しているのでぜひ! 理想駆動ラジオ Spotify プロダクト開発・運営の様子をお届 けするポッドキャストです。