Sunflat のブログ

ソフトウェア開発についての話題が多いかも

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

※ファイル削除処理等が含まれているので、万が一使いたい場合は、十分動作確認してからお願いします。