リードレプリカの遅延と一貫性
読み込みをレプリカに逃がした直後「自分の更新が消えた」と誤解される事故を、read-your-writesの実装パターンとラグ監視で防げます。
- 1.非同期レプリケーションではコミット直後にレプリカを読むと古い値が返る。これはレプリカが壊れているのではなく、適用がまだ追いついていないだけ。
- 2.read-your-writesは「書き込み直後だけプライマリに向ける」「LSN/タイムスタンプ待機」「セッション内は同じレプリカに固定する」の3系統で実装する。
- 3.レプリケーションラグは秒数ではなく適用位置の差分(LSN/GTIDの遅れ)で測るべきで、SLOとアラート閾値の根拠になる。
プライマリとレプリカ、遅延は「壊れ」ではなく「未到達」
同期/準同期/非同期レプリケーションのうち、実務で読み取りスケールに使われるのはほぼ非同期です。プライマリはWALをレプリカへ送るだけでコミットを確定させるため、コミット成功をクライアントに返した瞬間、レプリカにはまだその変更が届いていないことがあるのは仕様であり障害ではありません。
この「まだ届いていない量」をレプリケーションラグと呼びます。ラグは時間の遅れとして体感されますが、内部的には適用位置の差分です。
プライマリの現在位置: LSN 15000
レプリカが適用済みの位置: LSN 14820
ラグ = 15000 - 14820 (適用待ちのバイト/レコード数)
→ これがネットワークと再生速度に応じて何ミリ秒〜何秒かに変換される
秒数だけを見ていると誤解します。同じ「1秒遅れ」でも、書き込み量が少ない時間帯の1秒と、バッチ投入直後の1秒では意味が違う。ラグは秒数の監視だけでなく、適用位置の差分(バイト数やレコード数)でも追うべきというのはここに理由があります。
遅延は「プライマリの送信待ち」「ネットワーク転送」「レプリカでの再生(redo適用)」のどこでも積み上がります。特に見落とされがちなのが最後の再生律速で、レプリカのディスクI/Oやシングルスレッドの適用ループがボトルネックだと、ネットワークが速くてもラグは解消しません。
アプリが壊れて見える瞬間:read-your-writesの破れ
典型的な事故はこうです。ユーザーがプロフィールを更新→直後の一覧画面で読み込みレプリカを参照→まだ反映されておらず更新前の値が表示される。ユーザーには「保存したのに消えた」ように見えます。これはread-your-writes(自分の書いた内容は自分が読める) という一貫性保証が破れている状態です。
整合性モデルの階層で言えば、read-your-writesはセッション一貫性の一種であり、システム全体の強い一貫性(線形化可能性)までは要求しない、実務上狙いやすい落としどころです。実装パターンは大きく3つあります。
パターン1:書き込み直後はプライマリを読む
もっとも単純な方法は、書き込みを行ったセッションが、一定時間または一定操作数だけプライマリ(または最新性が保証された経路)から読むことです。
if (このセッションが直近 N 秒以内に書き込みをした)
→ プライマリへ read を向ける
else
→ レプリカへ read を向ける
実装はスティッキーな仕組み(セッションCookieやミドルウェアのルーティングルール)で行います。欠点は、書き込みが多いワークロードだとプライマリの負荷を十分に逃がせないことです。
パターン2:LSN/タイムスタンプ待機(read-your-writesの厳密版)
書き込み完了時にプライマリが返す位置情報(LSNやコミットタイムスタンプ)をクライアントが覚えておき、レプリカへの読み取りリクエストにその位置を添えます。レプリカは自分の適用位置がその値以上になるまで応答を待つか、追いついていなければエラー/フォールバックします。
1. 書き込み: プライマリが commit_lsn = 15000 を返す
2. 読み取り: クライアントが "as_of_lsn=15000" を付けてレプリカへ問い合わせ
3. レプリカ: 自分の applied_lsn >= 15000 になるまで待機(またはタイムアウトでプライマリへフォールバック)
これはハイブリッド論理クロックやTrueTimeのようなタイムスタンプ順序保証と発想が近く、「絶対時刻」ではなく「因果的に先行する書き込みへの追いつき」を条件にする点が要です。単なるwall-clockの待機(例えば「3秒待ってから読む」)は、ラグがその日の負荷で変動する以上、原理的に脆い代替策でしかありません。
LSN待機を採用する場合、レプリカが追いつかずタイムアウトした後の挙動を決めておく必要があります。プライマリへフォールバックするなら安全ですがプライマリ負荷が上がり、レプリカのまま古い値を返すなら一貫性が破れます。「待つ/諦める」の二択を暗黙にせず明示的に設計してください。
パターン3:セッション内で同一レプリカに固定する(モノトニック読み取り)
複数レプリカにラウンドロビンで読み取りを振ると、ラグの進み具合がレプリカごとに違うため、後のリクエストが前のリクエストより古い値を返す(時間が逆行して見える)ことがあります。これを防ぐには、同一セッション(同一ユーザー)の読み取りを常に同じレプリカへ固定し、少なくとも自分の観測内では時系列が逆転しないモノトニック読み取りを保証します。
| 手法 | read-your-writes | 実装コスト | プライマリ負荷 |
|---|---|---|---|
| 書き込み直後だけプライマリ読み | 保証される(時間窓内) | 低(ルーティング条件のみ) | 書き込み多いと増大 |
| LSN/タイムスタンプ待機 | 厳密に保証 | 中〜高(位置伝搬とAPI変更) | 増えない(待つのはレプリカ側) |
| セッション固定(モノトニック読み取り) | 保証しない(別の一貫性軸) | 低(ルーティングのみ) | 増えない |
3つは排他ではなく、LSN待機で厳密なread-your-writesを担保しつつ、通常時のレプリカ選択はセッション固定でモノトニック性も足す、という組み合わせが実務では一般的です。
モニタリング指標としてのレプリケーションラグ
ラグは「あるかないか」ではなく常に一定量存在するものとして扱い、SLOを設定して監視します。実務で見るべき指標は次の通りです。
- 適用ラグ(apply lag): レプリカの適用済み位置とプライマリの現在位置の差。LSN/GTIDの差分で測るのが最も正確。
- 受信ラグ(receive lag): ネットワーク経由でレプリカに届いているが、まだ適用されていない量。適用ラグとの差から「再生(redo)がボトルネックか、転送がボトルネックか」を切り分けられる。
- ラグの時系列トレンド: 瞬間値より、右肩上がりに増え続けているかどうかが重要。増え続けていればレプリカの適用速度がプライマリの書き込み速度に追いついておらず、いずれ無限に遅れる。
「レプリケーションラグとは何か」と問われたら、時間の遅れである以前に適用位置(LSN/GTID)の差分だと答えられれば十分です。read-your-writesを守る手段は、プライマリへの一時的な読み替え、書き込み位置を条件にしたレプリカ待機(LSN/タイムスタンプ待機)、セッションのレプリカ固定によるモノトニック読み取りの3系統に整理できます。これらは同期/準同期/非同期レプリケーションがデータ損失(耐久性)を扱うのとは別軸で、**読み取りの見え方(可視性)**を制御する仕組みだという区別が鍵です。
まとめ
リードレプリカの遅延はバグではなく非同期レプリケーションの構造的な帰結であり、対処すべきはラグそのものの排除ではなくアプリがラグを前提に一貫性を作り込むことです。read-your-writesは書き込み直後のプライマリ読み・LSN/タイムスタンプ待機・セッション固定の組み合わせで実装し、監視は秒数だけでなく適用位置の差分で行う。これらはCAP定理が示す可用性と一貫性のトレードオフを、読み取り経路の設計として日々具体化している作業だと言えます。
データベース Article
リードレプリカの遅延と一貫性を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
レプリケーション
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
read-your-writesは「書き込み直後だけプライマリに向ける」「LSN/タイムスタンプ待機」「セッション内は同じレプリカに固定する」の3系統で実装する。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「レプリケーション / 一貫性」に近いか確認する。
- 強みである「非同期レプリケーションではコミット直後にレプリカを読むと古い値が返る。これはレプリカが壊れているのではなく、適用がまだ追いついていないだけ。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。