【実務・中級編】 コミットタイムスタンプ – Cloud Spanner

Cloud Spannerの「コミットタイムスタンプ」は、単なる時刻記録ではない。分散システムの「真実」を刻む鍵だ。

エンジニア諸君、設計レビューでよく見る「とりあえず作成日時をアプリケーション側で `CURRENT_TIMESTAMP()` して保存する」という実装、Cloud Spannerを扱う上では即刻禁止だ。

なぜか? 分散環境において、各サーバーの時計が完全に一致することは物理的にあり得ないからだ。だが、Cloud Spannerには「コミットタイムスタンプ(Commit Timestamp)」という切り札がある。これを正しく理解し、使いこなすことこそが、真にスケーラブルな分散システムを構築する第一歩だ。

—

1. なぜ「アプリ側の時刻」ではいけないのか?

複数のインスタンスで稼働するアプリケーションから、ローカルの時刻をDBに書き込むとしよう。時計のズレ(クロック・スキュー)により、「データはAの方が後に作成されたはずなのに、Bの方がタイムスタンプが新しい」という矛盾が平然と発生する。

Cloud Spannerは、これをTrueTime APIによって物理的に解決している。Googleのデータセンター内に配置された原子時計とGPS受信機を用い、不確実性(Uncertainty)を許容しつつ、グローバルな順序付けを保証する。

コミットタイムスタンプとは、この「神の視点」から付与された、システムの整合性が取れた正確な時刻のことだ。

—

2. 実装の極意:`commit_timestamp` 列の設計

テーブル定義でこの機能を使うには、`OPTIONS (allow_commit_timestamp=true)` を指定する必要がある。

CREATE TABLE Orders (
OrderId STRING(36) NOT NULL,
UserId STRING(36) NOT NULL,
Amount INT64 NOT NULL,
— データの最終更新日時を管理するためのカラム
UpdatedAt TIMESTAMP OPTIONS (allow_commit_timestamp=true)
) PRIMARY KEY (OrderId);

【掟】アプリケーションからは時刻を渡すな

INSERTやUPDATEを行う際、アプリ側で時刻を生成してはならない。Spannerにその判断を委ねるのだ。

— 良い例:サーバー側で確定させる
INSERT INTO Orders (OrderId, UserId, Amount, UpdatedAt)
VALUES (‘order-123’, ‘user-456’, 1000, PENDING_COMMIT_TIMESTAMP());

`PENDING_COMMIT_TIMESTAMP()` は、「この行がコミットされた瞬間の時刻をサーバー側で埋めろ」というSpannerへの命令だ。これを使うことで、分散システムにおける「時刻の正当性」はSpannerが保証してくれる。

—

3. パフォーマンスと堅牢性のための設計パターン

パターンA:読み取り整合性の確保

「特定の時刻時点での状態」を再現したいとき、Spannerは最強のツールになる。コミットタイムスタンプをキーの一部やインデックスに含めておけば、履歴の追跡が極めて高速だ。

— 特定時刻以降の更新を取得するクエリ
— 読み取り専用トランザクションで実行すれば、パフォーマンスを犠牲にせずに整合性が取れる
SELECT FROM Orders WHERE UpdatedAt > ‘2023-10-01T00:00:00Z’;

パターンB:ホットスポットを避ける

コミットタイムスタンプを主キーの先頭に持ってくる設計は、アンチパターンだ。
常に現在時刻が書き込まれるため、特定のノードに書き込みが集中し、Spannerの強みである分散性能を殺してしまう。主キーには必ずランダム性を担保できるUUIDなどを選択し、タイムスタンプはあくまで属性(属性値)として扱うこと。

—

4. チーフアーキテクトからの忠告

最後に、現場でよくある失敗を一つ伝授する。

「コミットタイムスタンプをビジネスロジックの判定に使いすぎるな」

コミットタイムスタンプは「データベースがその事実を認識した時刻」であり、「ビジネスイベントが発生した正確な時刻」とは必ずしも一致しない。ネットワーク遅延や再試行によって数ミリ秒のズレが生じる可能性がある。厳密な時系列がビジネス上重要な場合は、別途 `EventTimestamp` のようなカラムを設け、アプリ側で生成するIDと組み合わせて管理すべきだ。

まとめ

1. `allow_commit_timestamp=true` を活用せよ。
2. `PENDING_COMMIT_TIMESTAMP()` を使い、アプリ側で時刻を生成するな。
3. 主キーの先頭にタイムスタンプを配置するな。

Cloud Spannerは、あなたが正しく使えば、この世で最も信頼できる分散データベースとして機能する。この機能を使いこなせば、もう「時刻のズレ」に頭を抱える必要はない。

さあ、コードに戻って設計を見直してくれ。君のシステムに「真の整合性」を刻み込もう。

コメント

タイトルとURLをコピーしました