こんにちは!技術の世界へようこそ。
今回は、Google Cloudが誇る世界最強の分散データベース「Cloud Spanner」の、とても奥深く、そして実務で必ず直面する重要なテーマについてお話しします。
テーマは「トランザクション(データ処理)と監査ログのレイテンシ保証」です。
「監査ログ?」「レイテンシ?」「トランザクション?」と、難しそうな言葉が並んでいて身構えてしまうかもしれませんね。でも、安心してください!
ここをクリアすれば、分散データベースの基本と「裏側で何が起きているのか」がバッチリマスターできますよ。
先輩エンジニアと一緒に、カフェでコーヒーでも飲みながらリラックスして読み進めてみてくださいね。
—
1. そもそも何が問題なの?(日常の出来事で例えてみよう)
まずは、私たちが解決したい「問題」を身近な例でイメージしてみましょう。
高級ホテルのフロントと防犯カメラのお話
あなたが高級ホテルのフロント係だとします。
お客様がやってきて「チェックインしたい」と言いました。
1. メインのお仕事(トランザクション):
お客様の宿泊カードを受け取り、部屋の鍵を渡す。
2. 監査・記録のお仕事(監査ログ):
「何時何分に、どのお客様へ、どの鍵を渡したか」を正確にセキュリティ日誌に記録し、支配人に報告する。
ここで、2つのやり方が考えられますよね。
- パターンA(完全同期):
日誌に細かく記入し、支配人のハンコをもらって金庫にしまうまで、お客様をカウンターの前で待たせる。
👉 結果:記録は完璧だけど、お客様はお待たせされてイライラ(レイテンシが悪化)。
- パターンB(完全非同期):
お客様にはすぐ鍵を渡し、「日誌はあとで暇な時に書けばいいや〜」と後回しにする。
👉 結果:お客様は爆速で案内できるけれど、もし直後に火事や停電があったら「誰に鍵を渡したか」の記録が消えてしまう(信頼性の崩壊)。
データベースの世界、特に世界中でお金を扱うようなシステム(銀行やECサイトなど)では、「お客様を待たせない(低レイテンシ)」と「不正や障害に備えて確実に記録を残す(監査ログの整合性)」を両立させなければなりません。
世界規模で動くCloud Spannerは、この難問をどうやって魔法のように解決しているのでしょうか?
—
2. Cloud Spannerの内部設計:同期と非同期の「黄金バランス」
Cloud Spannerは、この「速さ」と「確実性」を両立するために、内部の処理を絶妙な境界線で「同期」と「非同期」に分けています。
全体像を図にすると、次のようになっています。
[ アプリケーション ]
│ ① データ更新リクエスト
▼
┌────────────────────────────────────────────────┐
│ Cloud Spanner 内部 │
│ │
│ 【同期処理ゾーン:絶対に落とせないコア】 │
│ 1. 分散合意(Paxos)でデータを複製 │
│ 2. TrueTime で「確定した絶対時刻」を刻印 │
│ 3. トランザクション完了! │
│ └─▶ アプリへ「成功!」と即座に応答 (低遅延)│
│ │
│ 【非同期処理ゾーン:高信頼な追跡】 │
│ 4. 確定した履歴から「Change Streams」を生成 │
│ 5. Cloud Logging / 監査ログへ安全に転送 │
└────────────────────────────────────────────────┘
① コアデータは「同期」で瞬時に固める
データそのものを書き込むときは、複数のサーバー同士で「書き込んでいいよね?」と合意(これをPaxos合意と呼びます)を取ります。
この合意が取れた瞬間に、Googleが誇る超高精度な原子時計システム「TrueTime」を使って、「世界共通の絶対時間(コミットタイムスタンプ)」をデータにピトッと貼り付けます。
② 監査ログへの変換は「非同期」で軽快に受け流す
ここが最大のポイントです!
監査ログ(「誰が・いつ・何を変えたか」の外部記録)を外部のストレージに出力する処理までユーザーを待たせると、通信の遅延(レイテンシ)が大きくなってしまいます。
そこでSpannerは、「TrueTimeのタイムスタンプが刻まれた確定データ」から、後追いで非同期にログを取り出す仕組みを採用しています。
「非同期だと、順番が狂ったり消えたりしないの?」と不安になりますよね。
でも大丈夫。TrueTimeという「神の視点のタイムスタンプ」がすでにデータに刻まれているため、後から非同期でログを集めても、絶対に時間の前後関係が狂わないのです。
—
3. 実践!Spannerで監査ログ(変更履歴)を安全に取る方法
理屈がわかったところで、実際のCloud Spannerではどのようにこの仕組みを使うのかを見てみましょう。
Spannerには、データの変更を漏れなく・遅延なくキャプチャするための「Change Streams(チェンジ・ストリーム)」という機能が備わっています。
手順1:テーブルの変更を監視するストリームを作成する
まずは、DDL(データベースの定義文)で監査用のストリームを作ります。
— ユーザーの残高などを管理するテーブルがあるとします
CREATE TABLE UserWallets (
UserId STRING(36) NOT NULL,
Balance INT64 NOT NULL,
UpdatedAt TIMESTAMP NOT NULL OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (UserId);
— 【ここがポイント!】
— テーブルの変更(監査ログの元)を追跡するストリームを作成
— アプリケーションの書き込み処理を一切ブロック(遅延)させずに記録されます
CREATE CHANGE STREAM WalletAuditStream
FOR UserWallets;
手順2:データを安全に更新する(Pythonの例)
アプリケーションからデータを書き込むコードです。監査ログのために特別な二重書き込み(テーブルとログ両方に書く処理)をする必要はありません!
from google.cloud import spanner
def transfer_balance(instance_id, database_id):
spanner_client = spanner.Client()
instance = spanner_client.instance(instance_id)
database = instance.database(database_id)
def _update_tx(transaction):
# 1. データを更新(メイン処理)
# commit_timestamp を使うことで、Spannerが正確な時刻を自動刻印します
transaction.execute_update(
“UPDATE UserWallets ”
“SET Balance = Balance – 1000, ”
” UpdatedAt = PENDING_COMMIT_TIMESTAMP() ”
“WHERE UserId = ‘user_abc123′”
)
# 2. トランザクションを実行
# ここで Paxos 合意と TrueTime の刻印が「同期」で行われます
database.run_in_transaction(_update_tx)
print(“トランザクション完了!ユーザーへ即座に完了通知を返せます。”)
アプリ側はログ出力を待つ必要がないため、超高速(数ミリ秒〜十数ミリ秒)で終わります!
裏側では、先ほど作成した `WalletAuditStream` が、確定したトランザクションの変更差分を自動的かつ非同期にキャッチし、Pub/SubやBigQueryなどの監査ログ基盤へと届けてくれます。
—
まとめ:今日の重要ポイント!
最後に、今回学んだ「Spannerの基本と本質」を振り返りましょう。
1. 同期処理と非同期処理の役割分担
- コアトランザクションは同期(Paxos合意)で確実に永続化し、高速に応答する。
- 詳細な監査ログの転送は非同期で行い、ユーザーのレイテンシを犠牲にしない。
2. TrueTime(絶対時間)の存在
- 非同期でログを処理しても記録順序が絶対に狂わないのは、コミット時に「絶対時間」が刻印されているから。
3. Change Streamsの活用
- アプリ側で「テーブル更新」と「ログ書き込み」の2回リクエストを送る(二重書き込み)必要はなく、Spannerのネイティブ機能に任せるのが安全・高速の秘訣。
データベースの内部アーキテクチャを知ると、「なぜこの設定にするのか」「どうして高速に動くのか」がスッキリ見えてきますよね。
ここをクリアしたあなたなら、Cloud Spannerの基本設計はバッチリマスターできていますよ!自信を持って次のステップ(ストリームのデータパイプライン構築など)に進んでみてくださいね。応援しています!
コメント