トランザクションログとレプリケーション(物理 vs 論理)
レプリカが追従する仕組みを物理と論理の二層で正しく理解できます。WALシッピング・行/文ベース複製・CDCの原理と整合性保証を内部から解き明かします。
- 1.物理レプリケーション(WALシッピング)はログレコードをバイト単位でそのまま再生する。版・OS・ページ形式まで一致が前提で、レプリカは厳密に同一バイト像になるが選択的複製や異種DB間複製はできない。
- 2.論理レプリケーションは「どの行がどう変わったか」という論理変更へデコードして転送する。行ベースは確定値を、文ベースはSQL文を送り、テーブル単位の選択・版差・異種DB連携が可能になる。
- 3.CDCはこの論理デコードをストリームとして外部へ公開する仕組みで、整合性はLSN/GTIDによる位置管理とat-least-once+冪等な適用で担保する。
ログをどの抽象度で送るか
レプリケーションの本質は「プライマリで起きた変更を、レプリカで同じ結果になるよう再生する」ことです。決定的な分岐は、変更をどの抽象度で表現して転送するかにあります。同じWAL(先行書き込みログ)を起点にしても、送る粒度で性質がまるで変わります。
- 物理(physical): WALレコードを「ページのどのバイトをどう書き換えたか」という物理操作のまま送る。
- 論理(logical): WALを「どのテーブルのどの行が、どう変わったか」という行レベルの変更へデコードして送る。
物理は「ストレージの再現」、論理は「データの再現」です。この一点が、複製できる範囲・版互換性・整合性保証のすべてを規定します。
物理レプリケーション(WALシッピング)
物理レプリケーションは、プライマリが生成したWALレコードをそのままレプリカへ流し、レプリカが自分のページに同一の物理変更を適用します。これがWALシッピング(log shipping のストリーム版がストリーミングレプリケーション)です。
WALレコードは block 7 のオフセット 120 に 16 バイトをこう書く といった物理(または物理論理)操作を指します。レプリカはクラッシュリカバリの redo とまったく同じ機構でこれを再生するため、追加の解釈はほぼ不要で、CPU コストが低く遅延も小さいのが強みです。
物理レプリカは redo を進めながら同時に読み取りを受け付けます(ホットスタンバイ)。再生中のページを読むと「適用途中の中間状態」が見えそうですが、レプリカは適用位置を MVCC のスナップショットと連動させ、まだ可視化してはならない行を隠します。プライマリ側の VACUUM が、レプリカでまだ参照中の行版を消さないよう調整する仕組み(フィードバック)も併用されます。
物理方式の制約は「完全一致が前提」という点に尽きます。バイト操作をそのまま当てるため、次がすべて一致していなければなりません。
| 一致が必要なもの | 理由 |
|---|---|
| メジャーバージョン | WAL レコード形式・ページ形式が版で変わるため、混在再生は不可 |
| CPU アーキテクチャ/エンディアン | ページ上のバイト並びが一致しないと redo が破綻する |
| テーブル空間・ブロックサイズ | 物理位置(block / offset)を直接指すため |
結果として、物理レプリカは全データベースまるごとの複製になります。テーブルを選んで複製したり、版をまたいでアップグレードしたり、異種DBへ流したりはできません。その代わり、レプリカはプライマリと厳密に同一のバイト像になり、整合性のずれが原理的に入り込みません。
論理レプリケーション
論理レプリケーションは、WALを論理デコードして「行 R が INSERT/UPDATE/DELETE され、新旧の値はこれ」という抽象へ変換し、その論理変更を送ります。レプリカは受け取った変更を自分のSQL実行系で適用するため、物理レイアウトが一致している必要がありません。
これにより、物理方式では不可能だったことが可能になります。
- 選択的複製: 特定のテーブル・スキーマだけを複製する。
- 版・プラットフォーム差の吸収: 異なるメジャーバージョン間、異なるアーキテクチャ間で複製できる(ローリングアップグレードの基盤)。
- 異種DB・外部システムへの連携: 出力をプラグインで整形すれば、別種のDBや検索エンジン・データ基盤へ流せる。
論理変更の表現には大きく2系統があります。
行ベース(row-based)
各行の確定後の値(および UPDATE/DELETE の対象を特定する識別子)を送ります。SET price = price * 1.1 のような文も、デコード時点で各行の新しい値が確定しているため、レプリカ側は単純に値を書き込むだけで済みます。
複製の正しさは「プライマリとレプリカで同じ結果になる」決定性に懸かります。行ベースは確定値を送るので、NOW()・乱数・AUTO_INCREMENT の採番順といった非決定的要素がすでに評価済みです。だからレプリカで再評価してずれる余地がありません。多くのDBが既定を行ベースにするのはこのためです。
文ベース(statement-based)
実行されたSQL文そのものを送り、レプリカで再実行します。1 文が大量行を更新する場合に転送量が小さい利点がありますが、非決定性が致命傷になります。NOW()、RAND()、LIMIT 付きで ORDER BY が曖昧な更新、トリガやユーザー定義関数の副作用などは、プライマリとレプリカで異なる結果を生み、複製が静かに乖離します。
| 観点 | 行ベース | 文ベース |
|---|---|---|
| 送る内容 | 各行の確定値 | SQL 文そのもの |
| 決定性 | 高い(値は評価済み) | 低い(再実行で非決定要素がずれる) |
| 転送量 | 更新行数に比例 | 大量行更新でも文 1 つぶん |
| 異種DB連携 | しやすい | 方言差で困難 |
| 典型的な既定 | 推奨・既定 | 限定用途・非推奨寄り |
実務では、ほとんどの文を行ベースにしつつ、安全に決定的な一部だけ文ベースにする混合(mixed)も使われます。
CDC(変更データキャプチャ)
CDC(Change Data Capture)は、上記の論理デコードを外部向けの変更ストリームとして公開する仕組みです。狙いは「レプリカを作る」ことではなく、行レベルの変更イベントを検索インデックス・キャッシュ・データウェアハウス・ストリーム処理へ波及させることにあります。
実装方式は3つに大別できます。
| 方式 | 原理 | 弱点 |
|---|---|---|
| ログベース | WAL を論理デコードして変更を取り出す | DB ごとのログ解読が必要 |
| トリガベース | 変更を記録する監査テーブルへトリガで書く | 書き込みごとの追加負荷が大きい |
| ポーリング/差分 | 更新時刻列を定期スキャンして差分取得 | 削除を捕捉できず・遅延が大きい |
本命はログベースCDCです。WALは元々あるので本番の書き込み経路に追加負荷をほぼかけず、削除も含む全変更を順序付きで取り出せます。トリガやポーリングが持つ「削除を取りこぼす」「アプリ負荷を増やす」問題を構造的に回避できます。
CDC は通常「既存データの初期スナップショット」と「以後の変更ストリーム」を組み合わせます。スナップショット取得中も変更は流れ続けるため、両者の境界で重複や取りこぼしが起きやすい。正しい実装は、スナップショットを撮った地点の LSN を記録し、その地点以降のストリームと重なりを許して接合し、後述の冪等適用で重複を吸収します。
整合性はどう保証されるか
論理レプリケーションとCDCの整合性は、位置(オフセット)管理と適用の冪等性という2本柱で成り立ちます。
第一に、ストリーム上の各変更は単調増加する位置を持ちます。PostgreSQL なら WAL の LSN、MySQL なら GTID(グローバルトランザクションID)です。受信側は「どこまで適用したか」をこの位置で永続化(チェックポイント)します。障害で再接続したら、最後に確定した位置の直後から再送を要求できます。
第二に、ほとんどのストリーミングは at-least-once(最低 1 回、つまり重複しうる)です。再接続時に「確定済みの直前」から再送されるため、同じ変更を二度受け取りえます。したがって受信側は冪等な適用が必須です。具体策は次の通り。
- 主キー UPSERT: INSERT/UPDATE を「あれば更新、なければ挿入」にして、重複適用しても結果が変わらないようにする。
- 適用位置の比較: 受信側に最後に適用した LSN/GTID を保存し、それ以下の変更は捨てる。
- トランザクション境界の尊重: 1 トランザクションの変更群をまとめて適用し、途中状態を外部へ見せない(部分適用による不整合を防ぐ)。
受信ループ(at-least-once + 冪等適用):
loop:
batch = stream.read_until_commit() # 1 トランザクション分を集める
if batch.lsn <= applied_lsn: continue # 既適用なら捨てる(重複吸収)
apply_atomically(batch) # まとめて適用
applied_lsn = batch.lsn # 位置を永続化(チェックポイント)
stream.ack(applied_lsn)
論理・物理いずれの非同期レプリケーションでも、レプリカは原理的にわずかに古い(レプリカラグ)。さらにプライマリ障害時のフェイルオーバーでは、未送出ぶんが失われる可能性があります。「1 件も失えない」要件には準同期/同期や、過半数合意ベースの複製(合意アルゴリズム Paxos/Raft)が必要です。整合性と可用性のどこで線を引くかは CAP定理の問題に帰着します。
「物理と論理の違いを一言で」と問われたら、物理=WALレコードをバイト単位でそのまま再生(全DB・版一致が前提・低コスト)/論理=行レベルの変更へデコードして再生(選択複製・版差吸収・異種連携が可能)。CDCは論理デコードの外部公開で、整合性はLSN/GTIDによる位置管理とat-least-once+冪等適用で守る、と切り分けられると強いです。
まとめ
レプリケーションは「変更をどの抽象度で送るか」で性質が決まります。物理(WALシッピング)はバイト操作をそのまま再生して厳密同一のレプリカを安価に作りますが、版・プラットフォーム一致と全DB複製が前提です。論理はWALを行レベルへデコードするため、選択複製・版差吸収・異種連携が利き、その中でも行ベースは確定値ゆえに決定的、文ベースは非決定性のリスクを抱えます。CDCはこの論理デコードを外部ストリームとして公開する応用で、整合性はLSN/GTIDによる位置管理とat-least-once+冪等適用で担保します。どの方式も非同期である限りラグと欠落は残るため、最終的には可用性とのトレードオフ設計に行き着きます。
データベース Article
トランザクションログとレプリケーション(物理 vs 論理)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
レプリケーション
比較で見る軸
難易度: advanced / カテゴリ: データベース / タグ数: 5
導入後に効く点
論理レプリケーションは「どの行がどう変わったか」という論理変更へデコードして転送する。行ベースは確定値を、文ベースはSQL文を送り、テーブル単位の選択・版差・異種DB連携が可能になる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- データベース
- タグ数
- 5
判断チェックリスト
- 自社の用途が「レプリケーション / WAL」に近いか確認する。
- 強みである「物理レプリケーション(WALシッピング)はログレコードをバイト単位でそのまま再生する。版・OS・ページ形式まで一致が前提で、レプリカは厳密に同一バイト像になるが選択的複製や異種DB間複製はできない。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。