【実務・中級編】 読み取り専用と読み書きトランザクション – Cloud Spanner

Spannerの「一貫性」をハックせよ:読み取り専用トランザクションの真実と設計の最適解

Cloud Spannerを触り始めて最初に直面する壁、それは「RDBの常識が通じない」という感覚だ。特にトランザクションの設計において、Read-Write(RW)とReadOnly(RO)を適当に使い分けているなら、君のシステムはSpannerの真価を半分も引き出せていない。

今日は、Spannerのアーキテクチャの根幹である「TrueTime」と「分散トランザクション」の仕組みをベースに、エンジニアが実務で踏むべき「最適解」を叩き込む。

—

1. RWトランザクション:コストを支払って「最強の整合性」を買う

RWトランザクションは、Spannerの真骨頂である「外部整合性(External Consistency)」を保証するためのものだ。

なぜRWは重いのか?

RWトランザクションを開始すると、SpannerはPaxosグループ全体での合意形成を行う。書き込み時にはロックを獲得し、トランザクション完了までそのリソースを占有する。ここで重要なのは「競合」だ。頻繁に更新される行に対してRWを投げれば、レイテンシは跳ね上がり、スループットは死ぬ。

設計の鉄則

  • 「RWは最小単位で」: トランザクションの中で、外部APIを叩いたり、重い計算を挟むな。ロックの保持時間を1ミリ秒でも短くしろ。
  • 「ホットスポットを回避せよ」: インクリメントカウンターのような設計はSpannerでは最悪だ。物理的なシャードに負荷が集中する。キーの設計で負荷を分散させるのが、プロの仕事だ。

—

2. ROトランザクション:Spannerの「チート」を使いこなす

読み取り専用トランザクション(RO)は、Spannerが世界最強の分散DBたる所以だ。ここを理解せずにSpannerを語るな。

ROの秘密:スナップショット読み取り

ROトランザクションは、指定したタイムスタンプ(あるいは現在時刻)の「スナップショット」を読み取る。これにより、ロックを取得する必要が一切ない。 つまり、書き込み処理と読み取り処理が互いにブロックし合わないのだ。

実践:厳密な整合性が不要な場合の「Staleness」活用

もし、数秒程度の遅延が許容できるデータ(ダッシュボードや分析用データなど)であれば、`Exact Staleness`を指定しろ。

// 5秒前のスナップショットを読み取る(ロック不要で高速)
TimestampBound bound = TimestampBound.ofExactStaleness(5, TimeUnit.SECONDS);
try (ResultSet resultSet = dbClient.singleUseReadOnlyTransaction(bound)
.executeQuery(Statement.of(“SELECT FROM Inventory”))) {
// 読み取り専用のクエリ実行。競合を気にせず爆速で処理される
while (resultSet.next()) {
// …
}
}

この設定により、Spannerはローカルレプリカからデータを読み取ることが可能になり、レイテンシは劇的に改善する。

—

3. パフォーマンスと設計の「極限の勘所」

実務の現場で私がレビュー時に必ず指摘するポイントを列挙する。これを守るだけで、君のサービスの品質は一段上がる。

A. 「Read-OnlyはSingle-Useで」

読み取りのみの処理であれば、`ReadOnlyTransaction`を個別に生成するのではなく、`SingleUseReadOnlyTransaction`を使え。トランザクションの開始・終了のオーバーヘッドを削減できる。

B. 「RWからROへのフォールバックを考えるな」

よくあるミスが、「RWの中でクエリを投げて、必要なら更新する」というパターンだ。読み取りは極力ROで行い、最後に必要なデータだけをRWで更新する。「読み取りと更新の分離」こそが、高負荷時でもシステムを落とさないための防波堤だ。

C. 「強い整合性が本当に必要か?」

全てのクエリをデフォルトの整合性で実行するのは、ただの無駄遣いだ。

  • 決済処理: 強い整合性(デフォルト)。
  • プロフィール表示: `Exact Staleness` で数秒の遅延を許容し、スケーラビリティを確保。

この「妥協点」をビジネスサイドと合意形成できるエンジニアこそが、真のアーキテクトだ。

—

最後に:エンジニアへの提言

Spannerは、君たちがこれまで培ってきた「RDBのチューニング技術」を一度忘れさせることを要求してくる。

  • RW: ロックと競合に神経を尖らせ、最小限のスコープで完結させる。
  • RO: TrueTimeの恩恵を最大限に活用し、ロックフリーな読み取りを追求する。

この2つを使い分ける感覚が手に馴染めば、君はもうSpannerを恐れる必要はない。次は、どのクエリがインデックスを適切に使えていないか、`Query Plan`を読み解く段階へ進もう。

設計に迷ったら、常に「このクエリはPaxosグループ間で同期を取る必要があるのか?」と自分に問いかけろ。その自問自答の中に、答えはある。

コメント

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