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

更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話

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

 更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話

Avatar for Kensuke Taguchi

Kensuke Taguchi

September 15, 2026

Other Decks in Programming

Transcript

  1. 自己紹介 エムスリー株式会社 デジスマ診療 開発チーム 田口 健介 Kensuke Taguchi • 2022年にエムスリー入社。「デジスマ診療」の

    開発チームにジョイン • [ プロフィール画像 ] 2024年か チームリーダーとして、開発と チームビルディングに従事 • アイコンは実家の柴犬 © M3, Inc. 2025 3
  2. デジスマのアーキテクチャ概略 多層に走 サービス間の呼び出し • (元々)Kotlin + Spring Boot のマイクロサービスを Kubernetes

    (EKS) で運用 • 業務 API どうしも呼び合うため、1リクエストの裏で呼び出しが多層に走 © M3, Inc. 2025 6
  3. 課題① 起動直後のパフォーマンス 暖機が終わ までの性能低下 • 起動処理と、実行しなが のコード最適化で CPU を 使うため、起動直後は本来の性能が出ない

    • 起動直後は 20〜30 rps 程度しか捌けない • 割 当て 起動か 7〜8分は定常の3〜5倍 CPU を増やせば改善す が、暖機後は過剰な 割 当てにな というジレンマ 本番で新しく起動した1台の CPU 使用量(1分平均) © M3, Inc. 2025 8
  4. 1日のトラフィック傾向 診療時間に沿った山型のトラフィック 施設画面向け API 患者アプリ向け API 診療が始ま 時刻に、 階段状に立ち上が 午前9時/10時に診療が始ま

    医療機関が多く、昼休みを挟んだ午前・午後の二部構成にな グラフは平日1日・30分ごと。施設画面向け API のピークを 100 として正規化(両系列とも同一スケール) © M3, Inc. 2025 9
  5. 現状の対策と代償 暖機を前提にした設定の積み上が 積み上げた設定 何のためか Istio warmupDurationSecs 起動した Pod に流すリクエストを 少しずつ増やす

    代償 Pod を増やしてもすぐには効かない minReadySeconds 準備完了後もしば く古い Pod を残し、 全 Pod の入 替えに時間がかか 。 maxSurge / maxUnavailable 入 替えは一度に少しずつ 切 戻しにも同じだけかか 時間スケジュールに 混み合う前に、あ かじめ台数を増やす 最適な台数のチューニングが必要 スケーリング • 起動直後にリクエストが集中しない仕組みが必要 • サービスごとに、暖機の時間と起動台数を調整し続け ことにな ◦ © M3, Inc. 2025 対策のたびに別のとこ の設定を触 ことにな 10
  6. 課題② キャンセルの伝搬 上流が諦めても走 続け 処理 応答を待つ 呼び出し元 処理中 呼ば た側

    0s • © M3, Inc. 2025 誰も待っていない処理が続く 10s 30s 60s 上流がエラーを返した後も、下流は処理を続け ◦ • 10秒でタイムアウト → エラーを返す その間ずっと、リクエストを処理す スレッドと DB コネクションを掴んでい この結果、リクエストが詰ま 、最悪の場合 Pod がダウンす 11
  7. Go へのリプレイスという決断 既定でそうな 言語への移行 Kotlin でも実現でき Go だと既定でそうな • あ

    かじめコンパイルしておく仕組みを入 • ネイティブビルドなので、暖機が要 ない ◦ • ctx を引数で受け取 、渡すのが習慣 • ただしビルドに時間がかか うに ◦ 応答を待つ間ブロックしない う、処理経路を 全て書き換え ◦ API クライアントのライブラリも対応した • 実装す ときに自然と意識でき AI エージェントで移植を進め ◦ 「や な 今」と判断できた理由のひとつ ものへ乗 換え • どち も「でき 」。ただし、ずっと気をつけ続 け ことにな © M3, Inc. 2025 13
  8. 変化② キャンセルの伝搬 context で下流まで伝わ キャンセル const queryTimeout = 10 *

    time.Second func (h *Handler) Get(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // 上流が切れれば ctx も終了する ctx, cancel := context.WithTimeout(ctx, queryTimeout) defer cancel() rows, err := h.db.QueryContext(ctx, query) // DB クエリも止まる resp, err := h.client.Do(req.WithContext(ctx)) // 呼び出し先も止まる } • 受け取った ctx を渡していくだけで、DB クエリも、別の API の呼び出しも一緒に止ま • 渡すのが習慣になってい ため、多くのライブラリで自然に実装でき © M3, Inc. 2025 15
  9. 変化③ ビルドとベースの透明性 ビルド時間の短縮とベース部分の見通し CI ジョブの所要時間(中央値) Kotlin Go テスト 406 秒

    112 秒 イメージビルド 311 秒(Buildpacks) 204 秒(Dockerfile + BuildKit) • • ベース部分の透明性が上がった ◦ フレームワークが暗黙にやってく ◦ 便利さと引き換えの「内部で何をしてい か分か ない」は減った 成果物が単一バイナリにな 、イメージも起動も単純になった ◦ © M3, Inc. 2025 範囲が狭く、リクエストが通 道筋をコードで追え Buildpacks の うにビルド側の作 込みを気にしなくて い 16
  10. 同一性の担保と AI の使いどこ 振 舞いの同一性を担保す 仕組み 振 舞いを固定す 仕掛け AI

    の使いどこ • • ogen ◦ API 定義か サーバ・クライアントを生成 ◦ 定義は Kotlin 版と共通なので I/F の一致が ビルド時に担保さ • • 詳細は後述 仕様を決め 工程がなく、正解 (Kotlin 版の振 舞い)が既にあ • 「ついでの改善をしない」方針 ◦ • 速度を優先し、素直に再実装す 人がや べきは「どこを揃えないか」の判断 Golden Test と SQL の構文比較 ◦ © M3, Inc. 2025 ◦ 本番リクエストのミラーリング ◦ 言語リプレイスは AI と相性が い Kotlin のレスポンスを正解とし、比較 18
  11. 移植の進め方 リクエストミラーリングに 本番検証 • 本番のリクエストを Istio で複製して Go 版へ流す レスポンスは捨て

    ためユーザー影響はゼロ • 両者のレスポンスをログに落とし、あとか 構造を比較す • 全てのケースを網羅でき わけではない © M3, Inc. 2025 差分が出たとこ だけを直す 19
  12. 結果① 立ち上が と入 替え 起動直後のパフォーマンスの改善 • 再起動直後の1台に 100 rps を3分。成功率

    0% → 100% • 起動直後の1発目のレスポンスが 数十 ms ◦ • 全台のローリングアップデートが 約11分 → 1分未満 ◦ • Kotlin はレプリカ3〜4台で約11分。Go は1分粒度のメトリクスでは観測できない 短縮の効用は「速くなった」 ◦ © M3, Inc. 2025 暖機を待たずに応答でき 「や 直しが効く うになった」 緊急の切 戻しも同じだけ速い。デプロイのたびに開くリスクの窓が縮んだ 21
  13. 結果② キャンセルの伝搬 期限どお に切 応答を待つ 呼び出し元 0s © M3, Inc.

    2025 10秒でタイムアウト 処理中 呼ば た側 • うになった処理時間 課題②ではここまで走 続けていた 10s 10秒でタイムアウトした場合は下流の処理もキャンセルさ 30s 60s うに 22
  14. まとめ まとめ • 可用性を上げ ために何を直すかを洗い出した ◦ • Kotlin でもでき 。ただし気をつけ続け

    ことにな ◦ • © M3, Inc. 2025 立ち上が の遅さと、キャンセルの伝わ なさ Go は既定でそうなってい ので、意識す 観点が減 結果として課題は解決、可用性の向上に繋がった 24