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

Firestore → Spanner 移行 を成功させた段階的移行プロセス

Avatar for a-thug a-thug
September 08, 2025

Firestore → Spanner 移行 を成功させた段階的移行プロセス

データベースの負債解消への道のりLunch Talk
https://findy.connpass.com/event/365313/

Avatar for a-thug

a-thug

September 08, 2025
Tweet

Other Decks in Technology

Transcript

  1. ⾃⼰紹介 • 名前 ◦ 市島 慎吾 (Shingo Ichijima) • 会社

    ◦ 富⼠ゼロックス (2016/04 ~ 2018/08) ◦ バイセルテクノロジーズ (2018/09 ~ 2019/12) ◦ ラクスル (2020/01 ~ 2023/01) ◦ カウシェ (2023/02 ~ ) • 役割 ◦ Engineering Manager (Backend) • アカウント ◦ X: @shinichiji ◦ GitHub: @a-thug
  2. 今⽇お話しすること • 🔥 なぜFirestore→Spanner移行が必要だったのか • 🪜 どうやって移行したか • 🌟 移行にあたって幸運だった点

    • ⚠ トラブル及び解決策 • 🎉 結果とまとめ 具体の実装例などの詳細はZennの記事で! https://zenn.dev/kauche/articles/1e733da3748ee1
  3. 🔥 なぜFirestore→Spanner移⾏が必要になったのか 主な課題 • 🏢 事業フェーズの変化 ◦ データモデルが安定してきたため、スキーマレスの必要性が低下 ◦ NoSQLよりもRDBへの経験があるバックエンドエンジニアの⽅が多くなった

    • 🐌 Firestore固有の制限 ◦ クエリの制約 ◦ 複雑な検索の困難さ • 💰 コスト問題 ◦ 読み取り/書き込み従量課⾦で費⽤が急増 ◦ 2024年4⽉段階ではFirestoreにCUD(Committed Use Discount)は無かった
  4. なぜ移⾏を決断したのか • ⭕ Firestoreは初期選択として適切だった ◦ サービス開始した2020年当初、Spannerはnode単位でインスタンスを⽴てる必要があり⾼額 だった ◦ 成功するかもサービス⽅向性が定まるかも全く⾒えていない状況下で、当時は運⽤コストも抑 えたかった

    • 📊 事業成⻑でコスト問題が深刻化 ◦ 事業ピボットを経て、よりユーザのアクセスが増えるビジネスモデルへと変化した結果、コスト 問題の顕在化がかなり早くなった ◦ 「重要だけど緊急ではない」が「重要かつ緊急」となった • 🎯 コストや各種KPIの伸び⽅を考えると、今ここで着⼿するしかないとなった ◦ キャッシュするなど、⼀時的な対応をしていたが焼け⽯に⽔だった ◦ 根本的な解決が必要なタイミングとなった
  5. どうやって移⾏するか 移行にあたっての制約 • メンテナンスに入れることなく安全に移行したい • 今かかっているコストは早く下げたい • 移行に関する開発作業をやっている間であっても、機能開発は止めたくない 選択肢の⽐較 •

    全コレクション⼀気に移⾏ ◦ 移⾏⾃体は短期間で終わるが影響範囲が巨⼤でリスク⼤ ◦ リリースにあたっての予⾏演習やSpannerのウォームアップが必要 • ⭐ コレクション単位で段階的移⾏ ◦ ちょっとずつトラフィックを流していくのでリスクを分散できる ◦ Firestore, SpannerのTransactionが被ったときの扱いが難しい
  6. コレクション単位での段階的移⾏を選んだ理由 段階的移⾏のメリット • 🛡 影響範囲の限定 : 問題が起きても移行対象のコレクションのみ • 📈 段階的な効果実感

    : コスト削減を徐々に確認 • 📊 優先順位付けが可能 : 移行効果の高いもの、移行難易度が低いものから着手 • 🔄 ノウハウの蓄積 : 小さく移行を繰り返すことで、不確実性を減らす 優先順位の考え⽅ 1. 読み書きが低頻度 (例: 社内の管理画面からしかアクセスされない) 2. TransactionがSpannerのみで完結できて、移行がしやすい 3. 移行するとコストが大きく下がる 4. ユーザや注文データなど、サービスの根幹に近い
  7. 4段階の移⾏プロセス 1. Double Write(両DB書き込み) • FirestoreとSpanner両方に書き込み開始 • 先にFirestoreに書き込み、エラーがなければSpannerにも書き込む 2. データ移行

    • 既存データをスクリプトでFirestore→Spannerへ移行 3. Read切り替え • 読み取りをSpannerに切り替え ◦ FirestoreのKey VisualizerでReadがなくなっていることを確認する • 書き込みはFirestore, Spanner両方継続 • 2 → 4は一足飛びで可能といえば可能だが、瞬間的に古いCloud Runインスタンスへのトラフィッ クが残っている場合を考慮し、両方に書き込んでいた 4. Write切り替え • 書き込みをSpannerのみに変更 • これにてコレクションの移行を完了とする
  8. 🔥 当時(2024年5⽉)のカウシェの技術スタック及びチーム状況 • マイクロサービスとしては3サービス ◦ 最初に作られたECを担当するサービスがFirestoreを使っていた ◦ 残り2サービスは後発で、Spannerを使っていた • バックエンドはGoで書かれており、Cloud

    Runでホスティング • バックエンドエンジニアは⾃分含めて4⼈ • 移⾏作業専任として 0.5⼈/⽇ ◦ メインの移行作業は柴田芳樹さん(@yoshiki_shibata)
 ▪ Go言語 100Tips
 ▪ Web API設計実践入門 
 ◦ 改修箇所とオーバーラップしたり、コストの兼ね合いで早く移⾏したいコレクションは別 のメンバーで移⾏したりもあった
  9. 移⾏するにあたって幸運だったこと (1) • 切り戻しがしやすい環境だった ◦ Cloud Runでホスティングしていたため、Read切り替えを⾏ってエラーが出ていた場合 は⼀瞬で前のrevisionに切り戻すことができた • 移⾏作業がRepositoryレイヤーだけで済むようなコードベースのアーキテクチャ

    になっていた ◦ カウシェのコードベースではクリーンアーキテクチャを採⽤していた ◦ SpannerリポジトリがFirestoreリポジトリを内包し、メソッド単位で段階的に移行できる仕組みを採 用することができた • APIレベルでのE2Eテストがしっかり書かれていた ◦ 振る舞いが変わっておらず、移⾏によるデグレがないことを確認しやすかった ◦ テスト⽤データは正規のAPI経由で作ることが原則で、DB実装に依存する箇所はほぼ無 かったためテストがpassしてるなら問題ないよね、という判断がしやすかった
  10. 移⾏するにあたって幸運だったこと (2) • ⼤半の処理が冪等に作られていた ◦ FirestoreとSpannerではclient libraryがtransactionのAbortや競合を検知すると自動でリトライす る ◦ 冪等かどうかを検証するE2Eテストが存在していた

    • あまりFirestoreに依存していなかった ◦ コレクションの階層は深くて3階層だったので、NoSQLから乗り換えるにあたって頭を悩 ますべきことが少なかった ◦ 使われ⽅としてもNoSQLをフルに活⽤しているというよりも、RDBライクな使われ⽅をし ていた • Coding Agentの発達 ◦ 移⾏後半になると簡単なコレクションの移⾏作業は型化されて、Coding Agentでもでき るようになった
  11. ⚠ それでも移⾏中に直⾯したトラブル/課題と解決策 • ⚖ 1つのAPIの処理の中で、トランザクションを2回に分けてコミットしている箇 所があった ◦ 両DBのロールバックが難しい ◦ 特別な制御フローを実装


    ▪ 1回目のFirestoreトランザクションコミット時はSpannerへのコミットをスキップ
 ▪ 2回目のFirestoreトランザクションが成功してからSpannerに書き込みを行う • 🔍 Write切り替え後にデータの⽋損が発覚 ◦ ⾃分がCoding Agentでガンガン移⾏させていたコレクションで発覚 ▪ 全て完全に冪等にできていたわけではなかった... ◦ ビジネスロジック側でも冪等性を保つため、処理に使用するいくつかの値をハッシュ化してIDとし て使うことで一意性を担保
 ◦ BQに残っているデータをかき集めて突合し、データ復旧

  12. 結果:1年間かけたDB移⾏で達成できたこと • 💰 DB費⽤93%削減 ◦ Firestoreと⽐較して⼤幅なコスト削減 ◦ 稼働は0.5⼈/⽇なので、実質半年分の⼯数で出来たとも⾔える • ⚡

    パフォーマンス‧開発効率向上 ◦ 複雑なクエリの実⾏時間短縮 ◦ SQLの表現⼒による実装の簡素化 • 📊 分析クエリの効率化 ◦ 外部データセットが使えるのでBigQueryとの連携による効率化 ◦ Extensionsで使われていたCloud Run Functionsも不要になり、そのコストも浮いた
  13. 重要な学び ⼟台が⼤事! • 今回は移⾏にあたって、幸運な要素が多かった ◦ 切り戻しやすさ ◦ クリーンアーキテクチャによるDBの⼊れ替えやすさ ◦ E2Eテストというガードレール

    ◦ Firestoreへの依存度⼩ • これらの要素が⽋けていると、困難だった ◦ これらは移⾏を⾒据えたからやっていたわけではなく、インフラの初期選択の良さや開発効率 や品質を上げる取り組みとして根付いていた⽂化だった ◦ 逆に⾔えば脱Firestoreするならこれらをやっておくと良い、ということ ▪ 何かを変える変えないに関わらず、⼟台をちゃんと作っておくのは本当に⼤事
  14. まとめ 今⽇覚えて欲しいこと • 🔄 「重要だけど緊急ではない」は、いきなり「重要かつ緊急」になる ◦ 課題の認識が⼤事 ◦ 重要な問題については、緊急でなくとも⾝構えておく •

    🛡 不確実性を無くしていくプロセスでやっていこう ◦ やってみなくちゃ分からないというのは「それはそう」なので、少しずつやって分かる部 分を増やしていく • 🎯 ⼟台が最も⼤事 ◦ アーキテクチャ設計‧テスト‧依存の少なさが成功の鍵 皆さんの移行プロジェクトの参考になれば幸いです!