PostgreSQL | SQLite+MySQL経験者向け、30日で習得するPostgreSQL:プロレベル運用 - Day28 レプリケーション

SQL PostgreSQL
スポンサーリンク

Day28 後半のゴール

「“なんとなくレプリカ増やす”から、“設計して読ませる”に変える」

前半で、プライマリ/スタンバイ、WAL、読み取り分散のざっくり構造は掴めました。 後半では、「同期/非同期」「アプリからの読み先の決め方」「遅延の監視」「セキュリティとバックアップとの関係」まで含めて、“ちゃんと設計された読み取り分散”のイメージを作っていきます。

同期レプリケーションと非同期レプリケーション

「“書き込みを待つかどうか”で、安全性と速度が変わる」

PostgreSQLのレプリケーションには、大きく分けて「非同期」と「同期」があります。 ここは用語だけでなく、「何を守って、何を諦めるか」の話なので、少し丁寧にいきます。

非同期レプリケーションは、「プライマリがWALを書いたら、スタンバイに送るけど、スタンバイの反応を待たずにコミットを完了する」方式です。 アプリから見ると、書き込みは速いです。 ただし、プライマリが突然死んだ瞬間、「まだスタンバイに届いていない変更」が失われる可能性があります。 つまり、「ごく最近の数件〜数十件のトランザクションが消えるかもしれない」というリスクを受け入れる代わりに、速度とシンプルさを取る方式です。

同期レプリケーションは、「プライマリがWALを書いたあと、指定したスタンバイが“受け取ったよ”と応答するまでコミットを完了しない」方式です。 これにより、「プライマリが死んでも、少なくともその同期スタンバイにはデータが残っている」という状態を作れます。 一方で、スタンバイが遅いと、書き込み全体が遅くなります。 「安全性を上げる代わりに、レイテンシと構成の複雑さを受け入れる」方式です。

ここで大事なのは、「どちらが正解か」ではなく、「自分たちのサービスは“直近の数件が消える可能性”をどこまで許容できるか」を考えることです。 金融系や重要なトランザクションなら同期を検討する価値がありますし、一般的なWebサービスなら非同期で十分なことも多いです。

アプリから“どこに読みに行くか”を決める設計

「“全部レプリカ”ではなく、“クエリごとに読み先を選ぶ”」

読み取り分散を現実に使うとき、一番効いてくるのが「アプリ側の接続設計」です。 DBが勝手に振り分けてくれるわけではないので、「このクエリはプライマリ」「このクエリはレプリカ」と決める必要があります。

分かりやすい線引きは、「その読み取りが、直前の書き込みとどれだけ強く結びついているか」です。 ユーザーがプロフィールを更新した直後に表示する「自分のプロフィール画面」は、ほぼ確実に「さっきの更新が反映されている」必要があります。 ここをレプリカに投げると、レプリケーション遅延のせいで「更新前の情報」が見えてしまうことがあります。 なので、こういう「直後に読む系」はプライマリに読みに行くべきです。

一方で、「ランキング」「おすすめ一覧」「検索結果」「管理画面の集計」などは、数秒〜数十秒の遅れがあってもユーザー体験として致命的ではないことが多いです。 こういう「少し古くてもいい読み取り」は、積極的にレプリカに投げると効果的です。

実装としては、アプリ側で「読み取り用の接続プール」と「書き込み用の接続プール」を分けたり、ORMの機能で「read / write」を切り替えたりします。 大事なのは、「クエリを書くときに“これはどっちに投げるべきか”を意識する文化」をチームに根付かせることです。

レプリケーション遅延を“見える化”する

「“なんとなく大丈夫”ではなく、“数字で把握する”」

読み取り分散を安全に使うには、「今どれくらい遅れているか」を常に把握しておく必要があります。 PostgreSQLには、レプリケーションの状態を確認するためのビューが用意されています。

代表的なのが、プライマリ側の pg_stat_replication です。 ここには、各スタンバイごとに「どこまでWALを送ったか」「どこまで適用されたか」といった情報が載っています。 そこから、「プライマリとスタンバイの差分(バイト数)」や、「時刻ベースの遅延」を計算できます。

運用としては、例えば次のようなルールを決めます。 「レプリケーション遅延が5秒を超えたらアラート」「30秒を超えたらレプリカを読み取り対象から外す」などです。 これにより、「レプリカが遅れすぎているのに気づかず、古いデータをユーザーに見せ続ける」という事故を防げます。

ここでのポイントは、「レプリケーションは“動いているかどうか”だけでなく、“どれくらい遅れているか”を監視する対象だ」ということです。 読み取り分散をやるなら、監視とセットで考えるのがプロの運用です。

レプリケーションとバックアップの違い

「“コピーがある”と“過去に戻れる”は別物」

初心者がよく混同するポイントとして、「レプリケーションがあるからバックアップはいらないのでは?」という誤解があります。 これは危険なので、ここでハッキリ分けておきます。

レプリケーションは、「今の状態のコピーを別サーバに持つ」仕組みです。 プライマリでデータを消したり壊したりすると、その変更はWALを通じてスタンバイにも伝わり、スタンバイのデータも同じように消えたり壊れたりします。 つまり、「間違ってDELETEした」「アプリのバグでデータを壊した」といった論理的な事故には、レプリケーションは無力です。

バックアップは、「ある時点の状態をスナップショットとして保存しておき、後からそこに戻れる」仕組みです。 物理バックアップや論理バックアップ(pg_dumpなど)を取っておけば、「昨日の状態に戻す」「1時間前の状態に戻す」といったことができます。

なので、レプリケーションとバックアップは役割が違います。 レプリケーションは「可用性とスケール」のため、バックアップは「過去に戻るため」です。 本番運用では、この両方が必要です。

ここを理解しておくと、「レプリカがあるから安心」という危険な思い込みから抜け出せます。

セキュリティの視点から見たレプリケーション

「“コピー先も同じくらい守る”という当たり前を忘れない」

レプリケーションを組むと、「データが複数のサーバに存在する」ことになります。 これは、「守るべき場所が増える」という意味でもあります。

まず、スタンバイサーバ自体のアクセス制御が重要です。 「スタンバイだから本番ほど厳しくしなくていい」というのは完全にアウトです。 スタンバイには本番とほぼ同じデータが載っているので、侵入されたら情報漏えいの範囲は変わりません。

次に、レプリケーション用の接続ユーザーの権限設計です。 プライマリからスタンバイにWALを送るために、専用のレプリケーションユーザーを作ることが多いですが、 このユーザーには「レプリケーションに必要な最小限の権限」だけを与えるべきです。 アプリ用ユーザーと混ぜたり、スーパーユーザーにしたりするのは避けます。

さらに、ネットワーク的にも、「プライマリとスタンバイ間の通信を暗号化する」「特定のIPからしかレプリケーション接続を受けない」といった制御が必要です。 レプリケーションの通信経路が盗聴・改ざんされると、データの機密性・完全性が損なわれます。

セキュリティ目線で一言にまとめると、「レプリカは“本番のコピー”なので、本番と同じかそれ以上に厳しく守る」が基本です。

小さなサービスでの“現実的な読み取り分散”イメージ

「完璧じゃなくていい、でも“とりあえず1台”から一歩進む」

最後に、あなたが小さなWebサービスを運用していて、「そろそろDBが重くなってきた」という状況を想像してみます。 Day28までの内容を使って、“現実的な一歩目”を言葉にしてみましょう。

まず、プライマリ1台+スタンバイ1台の構成を用意する。 レプリケーションは非同期で始める(まずはシンプルさ優先)。 アプリ側で「書き込み用接続」と「読み取り用接続」を分ける。 ユーザー登録直後のプロフィール表示や、決済直後の確認画面などは、必ずプライマリから読む。 ランキングや一覧、検索結果などは、読み取り用接続(スタンバイ)に投げる。 レプリケーション遅延を監視し、一定以上遅れたらスタンバイを一時的に読み取り対象から外す。 バックアップは別途取り続け、「レプリケーション=バックアップではない」ことをチームで共有する。

これだけでも、「1台に全部乗せている世界」からはかなり前進です。 大規模になれば、ここに「スタンバイを2台に増やす」「同期レプリケーションを一部導入する」「自動フェイルオーバーを入れる」などが乗ってきますが、 Day28の時点では、「読み取り分散は“クエリの鮮度と一貫性を考えながら設計するもの”」という感覚が持てていれば十分です。

Day28 後半のまとめ

レプリケーションを使った読み取り分散を本番レベルで考えるときは、まず「非同期なら“直近の数件が消える可能性”を受け入れる代わりに速さとシンプルさを取り、同期なら“書き込みレイテンシの増加”と引き換えに安全性を上げる」というトレードオフを理解したうえで、アプリ側で「直後に読む必要があるクエリはプライマリ」「少し古くてもよいクエリはレプリカ」と読み先を設計し、さらに pg_stat_replication などで遅延を数値として監視しながら運用する。 そのうえで、「レプリケーションは“今のコピー”を増やす仕組みであって、誤削除やバグから“過去に戻る”ためにはバックアップが別途必要であり、レプリカも本番と同じレベルでセキュリティをかけるべき“もう一つの本番”だ」と理解しておくことが、Day28 後半の着地点になる。

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