rdiffでPostgreSQLの差分バックアップ
専有サーバのバックアップ(id:sunflat:20071108)だが、結局サーバ上のファイルはDARを使って差分バックアップを取ることにした。
DARはファイル内の差分は取ってくれない(1バイトでも更新すると、ファイル全体をアーカイブする)ようだが、まぁいいか。
とりあえずサーバ上の一時ディレクトリへ保存しておき、バックアップマシンから定期的にSFTPとかで吸い出すことにした.
ただ、PostgreSQLのデータは、サービスが動いている状態でディレクトリはそのままバックアップするだけではダメらしい。
WALファイルという、DBに対する処理履歴をすべて保存しておくポイントタイムリカバリという方法もあるらしいけど、かなりデータサイズが大きくなってしまいそう。
結局、pg_dumpツールを使って、普通にダンプファイルをバックアップしていくことに。
riff-backup (librsync?)に含まれる、rdiffというツールを使って、前回のダンプファイルとの差分(増分)を出して、差分だけをバックアップするようにした。
通常のdiffコマンドだと、ファイルサイズ100Mぐらいでサーバのメモリ(512M)を食い尽くしてしまう感じだが、ブロック単位で比較するrdiffは結構省メモリみたい。
しかし、rdiffが作成する差分ファイルは、1バイトでも更新されるとブロック全体が出力されるためか、サイズが大きい。-bオプションでブロックサイズを128バイトぐらいにするとだいぶマシになった(デフォルトは2Kバイト)。
rdiffは、まず片方のファイルからサイズの小さいsignatureファイルを作り、そのsignatureファイルともう片方のファイルを使って差分を作りだすので、前日のダンプファイル全体ではなくsignatureファイルのみを残しておけばよく、ディスクスペースも節約できる。
ちなみに、バックアップスクリプトはこんな感じに。--full(フルバックアップ)か--diff(増分バックアップ)オプションをつけて、1日ごとにcronで呼ぶ。
(簡易化したバージョンなので動作未確認)
#!/bin/bash BACKUPDIR=/var/backup/pgsql WORKDIR=$BACKUPDIR/work BLOCKSIZE=128 export PGUSER=postgres export PGPASSWORD=[postgresのパスワード] mkdir -p $BACKUPDIR mkdir -p $WORKDIR FNAME=pgdump-`date -I` case X"$1" in "X--full") # full backup pg_dumpall > $WORKDIR/dump || exit 1 rdiff signature -b $BLOCKSIZE $WORKDIR/dump > $WORKDIR/dump.sig gzip $WORKDIR/dump mv $WORKDIR/dump.gz $BACKUPDIR/$FNAME-full.gz echo generate $FNAME-full.gz ;; "X--diff") # diff backup if [ -f $BACKUPDIR/$FNAME-delta.gz ]; then echo already exists 1>&2 exit 1; fi pg_dumpall > $WORKDIR/dump || exit 1 rdiff delta $WORKDIR/dump.sig $WORKDIR/dump | gzip > $BACKUPDIR/$FNAME-delta.gz rdiff signature -b $BLOCKSIZE $WORKDIR/dump > $WORKDIR/dump.sig rm $WORKDIR/dump echo generate $FNAME-delta.gz ;; esac
※ファイル削除処理等が含まれているので、万が一使いたい場合は、十分動作確認してからお願いします。