バックアップは二種類ある
一言でいうと
論理バックアップは写真で、物理バックアップ + WALは動画です。写真では「昨夜の状態」までしか戻れず、動画なら「事故の30秒前」に戻れます。
なぜ必要なのか: まず2つの数字を決める
バックアップの設計は、ツールを選ぶことではなく、2つの数字に答えることです。
- RPO(目標復旧時点): どれだけのデータを失ってよいか
- RTO(目標復旧時間): どのくらいで再びサービスを提供しなければならないか
1日1回pg_dumpを取るなら、RPOは24時間です。最悪の場合、1日分が消えます。それが許容できるかが先で、そうでなければ、WALアーカイブが必要です。
RTOも忘れてはいけません。500GBのダンプをリストアするのに6時間かかるなら、バックアップがあっても、6時間はサービスが止まります。
論理バックアップ: pg_dump
pg_dump -Fc -d labdb -f labdb.dump # 커스텀 포맷 (압축·병렬 복원 가능)
pg_restore -d newdb labdb.dump
このコードブロックの韓国語コメントは、カスタム形式(圧縮・並列リストアが可能)という意味です。
- バージョンやアーキテクチャをまたげます: 16で取ったダンプを17に入れられます
- 一部だけを選んでリストアできます: テーブル1つだけ
- 人が読めます(
-Fp)
しかし、取ったその瞬間の写真にすぎません。昨夜のダンプと今日の午後の事故の間は、元に戻す方法がありません。そして、大きなDBでは、ダンプもリストアも数時間かかります。
ダンプは「移行」と「部分復旧」のためのもので、災害復旧の主力ではありません。
物理バックアップ + WAL: PITR
PostgreSQLは、すべての変更を、先にWAL(Write-Ahead Log)に書きます。データファイルよりWALが先です。そのため、次のような等式が成り立ちます。
어느 시점의 데이터 파일 복사본 + 그 뒤의 WAL 전부 = 그 뒤 아무 시점이나
このコードブロックの韓国語は、「ある時点のデータファイルのコピー + その後のWALすべて = その後の任意の時点」という意味です。
これがPITR(Point-In-Time Recovery)です。3つの部品が必要です。
archive_mode = on: 書き終わったWALセグメントを、安全な場所へコピー- ベースバックアップ:
pg_basebackupで取った、データディレクトリまるごと - リカバリー設定:
restore_commandでWALを戻し入れ、recovery_target_timeで止まります
archive_commandのルール
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
%p: 元のパス、%f: ファイル名- 成功したら0、失敗したら0以外の値を返す必要があります。成功したとうそをつくと、PostgreSQLがそのWALを削除し、その区間は永遠に復旧不可能になります
test ! -fで上書きを防ぎます。同じ名前の別の内容を上書きすると、復旧が黙って壊れます
失敗すると、PostgreSQLはリトライしながら、WALを削除しません。アーカイブ先が満杯になると、pg_walが増え続け、最終的にディスクが埋まります。pg_stat_archiver.failed_countを監視しなければ、黙って大きくなり、破裂します。
リカバリー手順
# 1. 베이스 백업을 복사한다 (원본은 건드리지 않는다)
cp -r /backup/base /var/lib/postgresql/restore
# 2. 어디서 멈출지 알려 준다
cat > restore/postgresql.auto.conf <<EOF
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2026-08-21 16:20:41+00'
recovery_target_action = 'promote'
port = 5433
EOF
# 3. 복구 모드로 시작하라는 표시
touch restore/recovery.signal
# 4. 띄운다
pg_ctl -D restore start
このコードブロックの韓国語コメントは、順に、ベースバックアップをコピーする(元は触らない)、どこで止まるかを伝える、リカバリーモードで開始するという印、起動する、という意味です。
recovery.signalがあると、PostgreSQLはリカバリーモードで起動します。WALを戻し入れながら、目標時点に到達すると、recovery_target_actionのとおりに動作します。
promote: 昇格して使えるようにします(デフォルト)pause: 止まって、確認する時間を与えます。確認してから決めたいなら、こちらが安全です
リストアのときに必ず守ること
絶対に、元の上にリストアしません。別のディレクトリ・別のポートで起動して確認してから、移します。復旧の目標時刻を間違えたときに、やり直す余地が残ります。
タイムラインが分岐します。リストア後に昇格すると、タイムライン番号が1増えます(00000002...)。元とリストアしたものは、その時点から別の歴史です。これを知らないと、あとで「WALが合わない」でさまようことになります。
よくあるミス
バックアップを同じディスクに置くこと。ディスクが壊れれば、両方とも壊れます。バックアップは、別の機器、できれば別の場所にある必要があります。
リストアの訓練をしないこと。これが最もよくあり、最も高くつきます。バックアップジョブが緑色であることと、そのバックアップで復旧できることは、別のことです。定期的に復旧リハーサルをしなければ、バックアップがあるとは言えません。
archive_commandの失敗を見ないこと。上に書いたとおり、ディスクが埋まります。
論理バックアップだけを置くこと。RPOが1日という意味ですが、たいていそのように合意したことはありません。
実務ではツールを使います
自分でスクリプトを組む代わりに、pgBackRestやBarmanを使います。増分バックアップ、並列圧縮、保持ポリシー、S3アップロード、そして何よりもバックアップの検証が入っています。このラボは、それらのツールが内部で何をしているかを見るためのものです。
1行にまとめると、こうです。
復旧してみたことのないバックアップは、バックアップではありません。