PostgreSQLのバックアップ手法のまとめ

PostgreSQLに格納したデータのバックアップとそのリカバリについて整理します。

# バックアップ手法の分類

おおまかに分けて、以下の種類があります。

* 論理バックアップ
* 物理バックアップ
    * オンライン・バックアップ
    * オフライン・バックアップ

## 論理バックアップ

データベースに格納されたデータをSQLの形で抽出します。
PostgreSQLをインストールすると付属している`pg_dump`コマンドを使って実施することができます。

postgresデータベースの中身をダンプする場合、

```
$ pg_dump postgres > dumpfile
```

として出力結果をパイプでファイルに書き出します。

ファイルの中身を見てみると、以下のような形でその時のデータベースの状態がSQLを使って再現できるような情報として記録されています。


```dumpfile
--
-- PostgreSQL database dump
--
＜略＞
--
-- Name: foo; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--

CREATE TABLE foo (
    a integer NOT NULL,
    b text
);
＜略＞
--
-- Data for Name: foo; Type: TABLE DATA; Schema: public; Owner: postgres
--

COPY foo (a, b) FROM stdin;
1   inserted
2   inserted
3   inserted
4   inserted
5   inserted
\.
＜略＞
```

こうして取得したデータをリストアするには、SQLを実行してやれば良いことになります。

restoreというデータベースにこのデータを復旧する場合は、

```
$ psql restore < dumpfile
```

としてあげればOKです。

なお、`pg_dump`の出力形式をデフォルトから変更した場合には、`psql`では読み込めないので`pg_restore`コマンドを使ってリストアします。

## 物理バックアップ

PostgreSQLのデータベースの実体はファイルの集まりです。このファイル自体をコピーすることを物理バックアップと呼びます。

PostgreSQLを起動した状態で行う場合をオンライン・バックアップ、PostgreSQLを停止させた状態で行う場合をオフライン・バックアップと区別して呼びます。

### オフライン・バックアップ
PostgreSQLは停止しているので、データベースの実体であるファイルが更新されることはありません。そのため、バックアップするのは`cp`や`rsync`コマンドを使ってPostgreSQLのデータが格納されたディレクトリごとコピーするだけです。高価なストレージを使っているなら、スナップショット機能を利用する方法もあります。

バックアップしたデータをリストアするには、コピーしたデータを使ってPostgreSQLを起動すればOKです。

### オンライン・バックアップ
PostgreSQLが起動しているので、データベースのファイルへの更新が行われています。そのため、単純にファイルをコピーするわけにはいきません。コピー中にファイルが更新されたとしても『何かしらの方法で』それをカバーする必要があります。

PostgreSQLの場合、トランザクションログであるWALを使ってカバーします。

即ち、バックアップを使ってリカバリするには、

1. バックアップしたデータを用意する
2. バックアップ中に発生したWALも用意する
3. バックアップしたデータを元にPostgreSQLを起動し、バックアップ中に発生した更新処理をWALから読みだし、未反映な処理をデータに反映する

という方法を取ります。ちょっと手間がかかりますね。
ですが、3.の部分はPostgreSQLが自動でやってくれるので、1.と2.のデータをバックアップとして取得しておけば良いです。

1.のデータは、オフライン・バックアップの時と同じく`cp`や`rsync`コマンドで取得します。
2.のデータはどうやって取得するのでしょうか？

2.のデータはWALアーカイブという形で取得しておきます。

#### WALアーカイブとは

何ぞ？ということですが、これはPostgreSQLが出力したトランザクションログ(WAL)ファイルを別の場所にコピーすることです。

WALファイルはデフォルト設定では直近の一定数しか保存されず、古くなったものは削除もしくは再利用されていきます。そのため、リカバリに使えるようにWALファイルを別の場所に保存しておく必要があります。

WALをアーカイブするのはどうするのでしょうか。

cronで定期的にコピーする？
それでも構いませんが、PostgreSQLにお任せすることができます。
それにはpostgresql.confに設定をしてPostgreSQLを起動すればOKです。

```postgresql.conf
wal_level = archive  # リカバリに使える情報を保存するようにminimal以外の値にしておく
archive_mode = on   # PostgreSQLによるWALアーカイブ処理を有効にする
archive_command = 'cp %p /archive/%f'  # WALアーカイブ処理時に使われるコマンドを指定する
```

後は、PostgreSQLが古くなったWALファイルを削除する前にアーカイブを実施してくれます。


#### オンライン・バックアップ時の手順

さて、これでリカバリ時に必要なWALファイルをバックアップしておくことができるようになりました。しかし、これだとリカバリ時に本当に必要なWALがどれなのかが分かりません。

これには、PostgreSQLの`pg_start_backup()`関数と`pg_stop_backup()`関数を使います。
具体的には、オンライン・バックアップを行う際に、

1. pg_start_backup()を実行
2. データベースのファイルをコピー（オフライン・バックアップと同様）
3. pg_stop_backup()を実行

という手順で行います。

pg_start_backup()関数とpg_stop_backup()関数を実行することで、バックアップが始まった時点と終わった時点のWALファイルがどれなのかがPostgreSQLによって記録されます。この情報はWALファイルと同じ場所に保存されるので、WALアーカイブを行っていれば同じくバックアップすることができます。

PostgreSQL 9.1からは、上記の3ステップをすべてひっくるめて行ってくれる`pg_basebackup`コマンドが用意されました。

`-D`オプションでバックアップ保存先を指定して実行するだけです。簡単！

```
$ pg_basebackup -D /backup
```

# バックアップ手法の比較

ものすごく単純化すると、以下のようになると思います（個人的見解）。

| バックアップ手法 | バックアップサイズ | バックアップ時間 | リカバリ時間| コスト | 業務影響 |
|:-----------|:------------:|:------------:|:------------:|:------------:|:------------:|
| 論理バックアップ |小|小|大|小|小|
| 物理バックアップ（オフライン）|大|中|小|小|大|
| 物理バックアップ（オンライン）|大＋α|中～大|中|中～大|小|

論理バックアップは、簡単に取得できてサイズも小さくなりますが、リカバリには一からデータをDBに投入し直すので時間がかかる傾向があります。

一方、物理バックアップはデータの実体をコピーしているためリカバリ時間は短いですが、サイズが大きくなることがネックです。さらに、業務影響を抑えようとすると、データ自体以外にアーカイブしたWALの考慮も必要となるため、運用コストがかかります。


特定のテーブルだけを保存したいなど、ちょっとしたバックアップなら論理バックアップがお勧めですが、データベース全体をバックアップするなら物理バックアップを使うことになるでしょう。

運用コストはしょうがない？

# 物理バックアップとリカバリを簡単にしたい！

そんなときは[pg_rman](https://github.com/ossc-db/pg_rman)が便利です╭( ・ㅂ・)و ̑̑ ｸﾞｯ

（これが言いたかった。。。）

ということで、次回はpg_rmanについて紹介します。

# 参考

* PostgreSQL 9.4 ドキュメント
[第24章バックアップとリストア](http://www.postgresql.jp/document/9.4/html/backup.html)