PostgreSQLのオンラインバックアップとリカバリ

自宅のサーバについて日次バックアップしたいなぁと考えていて、
そのバックアップ対象となるのがデータベースであるPostgreSQLということになりました。
Postgresはオンラインバックアップに対応しています。

ということで、オンラインバックアップをしてみたのと、
リカバリまで試してみました。そのまとめ。

バックアップの方式としてはpg_dumpコマンドを用いたものもオンラインでできるのですが、
WALアーカイブを用いたバックアップを試してみることにしました。

簡単に仕組みを説明しておくと、Postgesはデータベースの更新時、
トランザクションのログ、WALを残してから実行します。
そうすることで、データベースがクラッシュしてもWALを追うことで、リカバリできる仕組みになっています。
WALアーカイブとは、一定のタイミングでそのWALを別の場所にアーカイブしておく仕組みです。
例えば、データベースの実態が入っているディスクとは別のディスクにWALアーカイブを出力しておけば、
最悪データベースが入っているディスクが完全に破損しても、あるポイントまでリカバリできるようになります。

ちなみにPostgresはVer.9.4で検証しています。

Postgresの設定

  • postgresql.conf
    以下の設定を入れておきます
wal_level = archive
→walアーカイブを出力する設定
archive_command = 'cp %p /var/lib/pgsql/9.4/wal/%f' 
→walアーカイブを出力するときに実行するコマンド。WALをcpコマンドで所定の場所にコピーしている。
 %pはwalファイル名、%fはwalアーカイブファイル名が自動で入力される
max_wal_senders = 1
→同時に稼動するWAL送信プロセスの最大値
  • ph_hba.conf
    以下の設定を入れておきます。
local   replication     postgres  peer
→ローカルのpostgresユーザにレプリケーション権限を与える。

バックアップ

バックアップの流れ以下のとおりです。
* ベースバックアップを定期的に取る
* WALアーカイブを安全な場所に出力しておく
詳細を説明していきます。

ベースバックアップ

ベースバックアップとは、postgresの設定やら実際のデータベースの中身やらをまるまるバックアップする仕組みです。
以下のコマンドで実行できます(※)。

pg_basebackup -D [dirpath] -F t -x -z

※Ver.9.1からこのコマンドが使えるようです。
 その前まではちょっと複雑な手順が必要でした。(そこは書きません)

データベース管理ユーザ(デフォルトだとpostgres)で実行すること。

[オプションの説明]
-D :ベースバックアップ出力先パスを指定。出力先は空でなければならない。
  ディレクトリが存在しなければ作ってくれる。
-F t :出力する形式。tはtarで出力する。
-x :ベースバックアップ処理中、データベースが更新された際もファイルシステム上の
  ファイルは更新しないようにする。出力中はメモリ上で頑張る。
  (そうすることで、出力ファイルが変な状態になることを防ぐ)
-z :gzipで圧縮した状態にする

こちらのコマンドを実行すると、base.tar.gzというファイルが生成されます。
それを展開すると以下のものが入っています。

-rw-------. 1 postgres postgres     4  3月  1 21:49 PG_VERSION
-rw-------. 1 postgres postgres   206  3月  2 21:01 backup_label
drwx------. 6 postgres postgres    50  3月  1 21:50 base
drwx------. 2 postgres postgres  4096  3月  2 21:01 global
drwx------. 2 postgres postgres    17  3月  1 21:49 pg_clog
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_dynshmem
-rw-------. 1 postgres postgres  4218  3月  1 21:50 pg_hba.conf
-rw-------. 1 postgres postgres  1636  3月  1 21:49 pg_ident.conf
drwx------. 2 postgres postgres     6  3月  1 21:50 pg_log
drwx------. 4 postgres postgres    37  3月  1 21:49 pg_logical
drwx------. 4 postgres postgres    34  3月  1 21:49 pg_multixact
drwx------. 2 postgres postgres    17  3月  2 20:40 pg_notify
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_replslot
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_serial
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_snapshots
drwx------. 2 postgres postgres     6  3月  2 20:40 pg_stat
drwx------. 2 postgres postgres     6  3月  2 21:00 pg_stat_tmp
drwx------. 2 postgres postgres    17  3月  1 21:49 pg_subtrans
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_tblspc
drwx------. 2 postgres postgres     6  3月  1 21:49 pg_twophase
drwx------. 3 postgres postgres    58  3月  2 21:01 pg_xlog
-rw-------. 1 postgres postgres    88  3月  1 21:49 postgresql.auto.conf
-rw-------. 1 postgres postgres 21331  3月  1 21:50 postgresql.conf

postgresを触ったことがある人であれば、まるまるバックアップされていることがわかるかと思います。

WALアーカイブ

WALアーカイブ出力先を覗いてみると以下のようなファイルが出力されています。

-rw-------. 1 postgres postgres 16777216  3月  1 21:59 000000010000000000000001
-rw-------. 1 postgres postgres 16777216  3月  2 03:56 000000010000000000000002
-rw-------. 1 postgres postgres 16777216  3月  2 21:01 000000010000000000000003
-rw-------. 1 postgres postgres 16777216  3月  2 21:01 000000010000000000000004
-rw-------. 1 postgres postgres      302  3月  2 21:01 000000010000000000000004.00000028.backup

デフォルトだと、WALが16MBごとにアーカイブを残すようになっています。
なので、16MBのファイルがいっぱい有ります。

「〜.00000028.backup」について、これはベースバックアップ実行時に生成されるファイルです。
バックアップ履歴ファイルと言い、チェックポイント等、ベースバックアップ取得時の情報が入っています。
中身は以下のとおりです。

START WAL LOCATION: 0/4000028 (file 000000010000000000000004)
STOP WAL LOCATION: 0/40000B8 (file 000000010000000000000004)
CHECKPOINT LOCATION: 0/4000028
BACKUP METHOD: streamed
BACKUP FROM: master
START TIME: 2016-03-02 21:01:03 JST
LABEL: pg_basebackup base backup
STOP TIME: 2016-03-02 21:01:05 JST

〜.backの前半部分と同じファイル名の[000000010000000000000004]が一番最初に必要なファイルとなります。
[000000010000000000000004]とそれ以降生成されるWALアーカイブをリカバリのために取っておく必要があります。
その前のファイルは消してしまっても問題はありません。
(といっても、余裕があれば取っておいたほうが安心です。)

まとめると、リカバリに必要なのは以下のファイルです。
* ベースバックアップ(base.tar.gz)
* バックアップ履歴ファイル(000000010000000000000004.00000028.backup)
* .backupが付いている、元のファイル名以降のWALアーカイブ
 (000000010000000000000004以降のWALアーカイブ)

リカバリ

リカバリの流れは以下のとおりです。
* postgresのサービスを停止する
* データベースクラスタを消去する
* ベースバックアップファイルをデータベースクラスタの場所に展開する
* ベースバックアップの中身に入っているWALは一旦削除する
* WALアーカイブを適当な場所に配置する
* recovery.confファイルを作成する
* postgresのサービスを起動する
詳細を説明していきます。

postgresのサービス停止

RHEL7系のsystemdであれば以下のとおりです。

systemctl stop postgresql-9.4.service

データベースクラスタ

データベースクラスタとはデータベースが入ってる場所です。
デフォルトだと、/var/lib/pgsql/[バージョン]/dataです。
この中身をまるまる削除します。

rm -rf /var/lib/pgsql/9.4/data/*

(ディスクに余裕があれば、削除ではなく別の場所に移動する等のほうがいいと思います)

ベースバックアップファイル

データベースクラスタのディレクトリ内にベースバックアップを展開します。

tar xvf  base.tar.gz

ベースバックアップの中にWALが入っているので削除します。
(ベースバックアップ取得時のWALは最新のものではないため)
pg_xlogの中身です。

rm -rf /var/lib/pgsql/9.4/data/pg_xlog/*

(こちらもディスクに余裕があれば、削除ではなく別の場所に移動する等のほうがいいと思います)

WALアーカイブの配置はこの後の設定で場所を指定するので、どこでも良いです。
postgresユーザが読み込み権限をもっている場所である必要があります。

recovery.confファイル

データベースクラスタの場所に作成します。

vim /var/lib/pgsql/9.4/data/recovery.conf

[中身](以下の1行のみでOK)
restore_command = 'cp /tmp/wal/%f %p'

WALアーカイブが置いてある場所はここで指定します。
上記の場合、WALアーカイブの配置先として”/tmp/wal”を指定しています。

postgresのサービス起動

さて、あとは起動するだけです。

systemctl start postgresql-9.4.service

postgresのサービス起動時にWALを読み込み、自動でリカバリをしてくれます。
postgresのログを見たところ以下の通りログが出力されていました。

2016-03-02 21:39:20.008 JST 2713 56d6def8.a99-1 0 LOG:  データベースシステムは中断されました: 今回は 2016-03-02 21:01:03 JST までは到達しています
2016-03-02 21:39:20.008 JST 2713 56d6def8.a99-2 0 LOG:  見つからなかった WAL ディレクトリ "pg_xlog/archive_status" を作成しています ... 
2016-03-02 21:39:20.245 JST 2713 56d6def8.a99-3 0 LOG:  アーカイブリカバリを開始しています
2016-03-02 21:39:20.269 JST 2713 56d6def8.a99-4 0 LOG:  ログファイル"000000010000000000000004"をアーカイブからリストアしました
2016-03-02 21:39:20.352 JST 2713 56d6def8.a99-5 0 LOG:  0/4000090のREDOを開始します
2016-03-02 21:39:20.436 JST 2713 56d6def8.a99-6 0 LOG:  0/40000B8 でリカバリー状態の整合が取れました
cp: `/tmp/wal/000000010000000000000005' を stat できません: そのようなファイルやディレクトリはありません
2016-03-02 21:39:20.441 JST 2713 56d6def8.a99-7 0 LOG:  0/40000B8のREDOが終わりました
2016-03-02 21:39:20.464 JST 2713 56d6def8.a99-8 0 LOG:  ログファイル"000000010000000000000004"をアーカイブからリストアしました
cp: `/tmp/wal/00000002.history' を stat できません: そのようなファイルやディレクトリはありません
2016-03-02 21:39:20.468 JST 2713 56d6def8.a99-9 0 LOG:  選択された新しいタイムラインID: 2
cp: `/tmp/wal/00000001.history' を stat できません: そのようなファイルやディレクトリはありません
2016-03-02 21:39:20.597 JST 2721 56d6def8.aa1-1 0 (postgres, postgres, [local], [unknown])FATAL:  データベースシステムは起動しています
2016-03-02 21:39:21.119 JST 2713 56d6def8.a99-10 0 LOG:  アーカイブリカバリが完了しました
2016-03-02 21:39:21.598 JST 2722 56d6def9.aa2-1 0 (postgres, postgres, [local], [unknown])FATAL:  データベースシステムは起動しています
2016-03-02 21:39:22.003 JST 2713 56d6def8.a99-11 0 LOG:  MultiXact member wraparound protections are now enabled
2016-03-02 21:39:22.008 JST 2711 56d6def7.a97-3 0 LOG:  データベースシステムの接続受付準備が整いました。
2016-03-02 21:39:22.008 JST 2724 56d6defa.aa4-1 0 LOG:  自動バキュームランチャプロセス

リカバリ、つまりWALからREDOしているのがわかるかと思います。

以上で終わりです。結構簡単ですね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です