【セッションレポート】「 大規模決済中継システムにおける Cloud SQL から Spanner への移行と苦労」に参加しました

# はじめに
本記事はGoogle Cloud Next Tokyo 2024 のDay1(8/1)において NTTデータ の 鳥海さん と 松井さん が講演された「大規模決済中継システムにおける Cloud SQL から Spanner への移行と苦労」のレポートです。

# 公式セッション紹介
> NTTデータでは決済代行ソリューション「Omni Payment Gateway」を提供しています。
> 本システムでは開発初期より Cloud SQL for MySQL を使用してきましたが、Spanner への移行を決意しました。
このセッションでは、なぜ Cloud SQL から Spanner へ移行するのか、どのように移行したのか、移行にあたって苦労したポイントをご紹介します。

# 発表資料
- アーカイブ動画は9月に公開されるとのこと(Google Cloud Next Tokyo 2024として)

# 概要／おすすめポイント
既存のシステムでなぜ元々Cloud SQLを選定したのか、なぜ今移行が必要とされているか、そしてなぜ移行先として Cloud Spannerを選択されたのかが順を追って説明されています。
また、設計で気を付けた点、移行で気を付けた点、移行後の監視で気を付けた点、なども説明されており、Cloud Spannerへの移行だけでなくデータベースの移行を検討する際のノウハウが詰まっていると思いました。
アーカイブ動画が公開されたら是非見てみてください。

# セッション内容の紹介

#### 移行先データベース選定

1. なぜ元々Clou SQLを選定したのか
    - マルチクラウドを意識(MySQLという標準的なエンジンを選定)
    - スモールスタート(コストをかけたくない)
    - 高可用性不要(SLAの99.95%で良い)
1. なぜ今移行が必要とされているか
    - メンテナンスでのサービス停止が辛い
    - 今後のユーザ増加見込み(**50倍**になる可能性が?)
    - 全体としての高可用性を 99.99% に、また将来的なマルチリージョン化を指向
1. なぜ移行先としてCloud Spannerを選定したのか
    - SLA 99.999%(マルチリージョン時)
    - マルチリージョンで完全同期
    - メンテナンスダウンタイム なし
    - スケール 無制限・無停止

当初の選定事由であるコストやマルチクラウドといった制限がない状態において Google Cloud上でリレーショナルデータベースを選択する場合には **Cloud Spanner** は非常に強力ですね。なお、Cloud Spannerはコストについても昨年 [価格性能比の改善](https://cloud.google.com/blog/ja/products/databases/announcing-cloud-spanner-price-performance-updates) が行われており、ある程度のスモールスタートにも適した形になっていると認識してます。

余談ですが、サービスを開始して「今後のユーザ増加見込み」で新たにアーキテクチャも設計し直して移行する、というのはとても幸せなことですね。~~大体スケールアップ・バージョンアップして単純更改が~~

#### Cloud Spannerへのエンジン変更における設計ポイント

1. テーブル構造
    - 主キー設計：ホットスポットとなりうるためULID(Universally Unique Lexicographically Sortable Identifier)を反転(単調増加を避けるため)
    - セカンダリインデックス設計：挿入がメインとなるため最低限に
1. クエリ
    - 時系列検索：論理シャーディングで対応
    - 検索全体：主キー・セカンダリインデックスでの簡単な検索のみに、**複雑な検索はBigQuery**に
1. 非機能
    - コスト設計：**実機で負荷をかけて**コスト検証、シングルリージョンとマルチリージョンでは同じ負荷でもCPU負荷が変わってくる
    - レイテンシ：簡単な検索でも 十数msec(MySQLよりも遅くなる)、マルチリージョンはシングルリージョンの1.5倍程度

面白いな、と思ったのはCloud Spannerではデータ挿入を優先して、検索は単純なSQLに制限、複雑なものはBigQueryにアウトソース、という形です。Cloud Spannerではwrite(挿入)がスケールするので、データやサービスの高可用性や性能はCloud Spannerで確保しつつその他の部分を BigQuery で補完していく、という利用の仕方はそれぞれの特長をうまく利用しているのかな、と感じました。
また、[BigtableでのSQLサポートが発表](https://cloud.google.com/bigtable/docs/introduction-sql?hl=ja) されたので今設計するならそちらでも良いのかな、と思いました(クエリや利用の仕方にもよりますが)。

また、コストの部分で実際に実稼働相当の負荷をかけて実機で確認した、という点も、Cloud Spannerのコスト見積もりは難しいと聞いているので妥当な選択だと感じました。

#### 移行おける設計ポイント

移行において重要な点としては、移行前移行後でデータの齟齬がないこと、という点が一番重要な点となります。BatchとDataflowを利用してデータ移行を行い、並行してkafkaを利用してCloud SQLとClous Spannerへの二重書き込みを行っていました。
BatchとDataflowの移行では、不整合検知とデータ補正をそれぞれプログラムを走らせて実施されていたとのことです、テーブル構造を変えないといけないので単純なデータ移行はできないという事ですね。

また、ゼロダウンタイムでの移行を想定されていたので CDC(Change Data Capture) のような形ではなく、二重書き込みを選択されたのかと思いました(要件によって大きく変わる箇所と思います)。

#### 移行後のリソース監視

Cloud Spannerでのリソース監視ではQuery Insightsによるダッシュボード監視でかなり詳しく確認することができる、というお話でした。
先日のDB Tech ShowcaseでGoogle Cloudの [佐藤さんが発表されていた小ネタ](https://qiita.com/asahide/items/1b3bb4b907871aa51394) でも取り上げられていた、Queryへのタグ付けやロック分析がGUIベースで行えるのでとても確認しやすいとのことでした。

#### その他の問題

以下の課題が発生したとのことでした。
1. 性能試験時の謎ロック
    - ロックが発生しないはずのシナリオでロックが発生
    分散トランザクションにおいてコミット時に書き込みが完了していない状況でもデータが記録されると完了を返すが、同じデータへの次のトランザクションが待機されてしまう、という事象。試験前に [ウォームアップ](https://zenn.dev/google_cloud_jp/articles/1adfdfc1fa5a6c) を行っておくことで防ぐことができるそうです
1. セッション管理
    - いわゆるコネクションプーリングで、一つのコネクションを生成するのは 数百msec かかるため、あらかじめセッションプールを作成しておき、トランザクションごとにセッションプールからセッションを取り出して終わったら返す、という形です。十分に大きな数を 最小値＝最大値 として設定されたそうです。余分なセッションが常時接続されているコストは大きく影響がないことを、実際にセッションを作成して確認したとのことでした。また、プール内のセッション利用数はOpenTelemetryで確認できるとのことです

ロックのところはOracle Databaseの遅延ブロッククリーンアウトを思い出しました。また、セッション管理(セッションプール)も 最小値＝最大値 というのは昔から変わらないんだな、というところは再確認できました。

# まとめ

おすすめポイントにも書きましたが、設計時から選択時のポイントなど含めて流れで説明されていたのでとても理解しやすかったです。今回は Cloud SQL for MySQLから Cloud Spannerの事例でしたが、評価軸などはほかの移行事例でも活用できるのでは、と思いました。
9月のアーカイブ公開が待ち遠しいですね。

本質ではないですが、 それぞれ選択肢を出して評価して選択する というプロセスがなじみ深かったです・・