LoginSignup
17
14

More than 5 years have passed since last update.

Herokuが開発したWAL-Eを使って、AWSでPostgreSQLのバックアップを取る

Last updated at Posted at 2013-02-25

今回はEC2インスタンスのOSとしてUbuntuを選択。
CentOS系のAmazon Linuxだとデフォルトで入るバージョンが色々古くてめんどくさいからね。でもapt-getyumに変えたらだいたい動くんじゃないかと期待。

wal-eとはもともとHerokuがAWS上でpostgresqlのバックアップを取るために開発していたPythonスクリプト。EC2上で走っているPostgreSQLのデータをS3に保存してくれる。
S3にデータ送信すること自体がscpなどを使えず厄介なので、そこを解決してくれているところもあるのだが、単にs3cmd等でバックアップを取るのと違ってデータを圧縮して送ってくれていたり、今あるバックアップ一覧をコマンド一発で見れたりする部分が良いと思う。それ以上には詳しく調べてないけど、HerokuはAWS上でPostgreSQLを動かすノウハウは一番あるのではないかと言うようなサービスなので、なんとなく良さそうに思えるw

wal-eのインストール

最新を入れたい人は、gitのソースコードから入れる。

git clone https://github.com/wal-e/wal-e.git
cd wal-e
sudo python setup.py install

ちょっと古くてもいい人は、以下のようにやると良い。(pip派はpip使って下さい)

sudo apt-get install python-setuptools
sudo apt-get install python-dev libevent-dev
sudo easy_install wal-e

ちなみに、postgresqlapt-getで入れた。そしたらVersion9.1.8が入った。最新の9.2が使いたかったら自分でやること。

$ sudo apt-get install postgresql
$ psql --version
psql (PostgreSQL) 9.1.8

wal-e用設定

https://github.com/wal-e/wal-e にそのまま従って設定

sudo su -
umask u=rwx,g=rx,o=
mkdir -p /etc/wal-e.d/env
echo XXXXXXXXX > /etc/wal-e.d/env/AWS_ACCESS_KEY_ID
echo xxxxxxxxxxxxxxxxxxxxx > /etc/wal-e.d/env/AWS_SECRET_ACCESS_KEY
echo 's3://your-bucket-name/backups' > /etc/wal-e.d/env/WALE_S3_PREFIX
chown -R root:postgres /etc/wal-e.d

ここyour-bucket-nameはs3のUS Standardに作る。(wal-eは現状us-eastでしか動かない。Issueは出来ているのでもうすぐ出来るようになるかもしれないけれど。)
さらに以下のブログによると悪意のあるデータ削除対策としてVersioningを有効にすると良いらしい。
http://blog.opbeat.com/2013/01/07/postgresql-backup-to-s3-part-one/

wal-eでバックアップを取る

まず必要な環境をInstall

sudo apt-get install daemontools pv lzop mbuffer

wal-eでログを取るためにはwal_levelがarchive以上が必要。
wal_levelはminimal(デフォルト), archive, hot_standbyの順に上がっていく。
http://www.postgresql.jp/document/9.1/html/runtime-config-wal.html

今回はarchiveでやるが、hot_standbyにするときは、
http://blog.gomiso.com/2012/02/13/adventures-in-scaling-part-3-postgresql-streaming-replication/
を参考にすると良さそう。

/etc/9.1/main/postgresql.conf
#------------------------------------------------------------------------------
# WRITE AHEAD LOG
#------------------------------------------------------------------------------

wal_level = archive # hot_standby in 9.0 is also acceptable
archive_mode = on
archive_command = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e wal-push %p'
archive_timeout = 300

と設定して、リスタート!

sudo /etc/init.d/postgresql restart

なお、archive_timeoutは少し大きめの5分間隔にした。本当にデータを失いたくないなら、hot_stanbyにするべきだし、archive-modeで1分は短すぎてパフォーマンス的に嬉しくない気がする。詳しくはpostgresqlのドキュメント参照。

archive_commandでは念のため、envdirwal-eコマンドをfull pathで指定しておくと良いと思う。自分はこのコマンドが走るときだけ、/usr/local/binがPATHに入ってないことに気づかずにだいぶハマった。なお、archive_commandにおける%pは格納されるファイルの絶対パスを表す。
http://www.postgresql.jp/document/9.1/html/runtime-config-wal.html#GUC-ARCHIVE-COMMAND

一応archive_commandに設定したwal-pushがちゃんと動くか確かめておこう。(0000000100000000000000B4の部分は各自の環境で、ls /var/lib/postgresql/9.1/main/pg_xlogした結果の中から一つ選ぶ。)

sudo su - postgres
envdir /etc/wal-e.d/env wal-e wal-push /var/lib/postgresql/9.1/main/pg_xlog/0000000100000000000000B4

うまくいってそうだったらbackup-pushしてみる。

sudo su - postgres
envdir /etc/wal-e.d/env wal-e backup-push /var/lib/postgresql/9.1/main/
envdir /etc/wal-e.d/env wal-e backup-list  # ちゃんととれたか確認

ここで、/var/lib/postgresql/9.1/main/はPostgreSQLのデータが入ったディレクトリのこと。postgresql.confに以下の様な記述があるはず。

/etc/postgresql/9.1/main/postgresql.conf
data_directory = '/var/lib/postgresql/9.1/main' 

ちなみに自分たちは、これを追加したEBS上に設定しなおしている。

バックアップタスクをcronに登録

sudo su - postgres
crontab -e

とし、以下のように打つ。

0 4 * * * /usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e backup-push /var/lib/postgresql/9.1/main/

これで毎日午前4時にバックアップがとられる。
(dateコマンドを打ってTimezoneがJSTになっていることを確認すること)

JSTにするには以下のようにすれば良い。

sudo mv /etc/localtime /etc/localtime.default
sudo ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

バックアップからのリカバリ

バックアップからのリカバリはこれが参考になる。
https://gist.github.com/ruckus/2293434

とりあえずリカバリ実験用に無理やりpostgresをkillする。

sudo pkill -9 postgres

ここからリカバリするには、

sudo su - postgres
cp /usr/share/postgresql/9.1/recovery.conf.sample /var/lib/postgresql/9.1/main/recovery.conf
emacs /var/lib/postgresql/9.1/main/recovery.conf

restore_commandにwal-fetchを設定する。

recovery.conf
restore_command  = '/usr/bin/envdir /etc/wal-e.d/env /usr/local/bin/wal-e wal-fetch %f %p'

これで、sudo /etc/init.d/postgresql startpg_ctl startなどでPostgreSQLを再起動させたらWALが残っているところまで(ほぼ全部)復元され、サービスが再開される。

なお、DBがrecoveryされたら、recovery.confrecovery.doneという名前になる。

データそのものが失われてしまっていた場合

ハードディスクが飛んでデータも消えちゃったことを想定し、

rm -rf /var/lib/postgresql/9.1/main/

する。
これは、

umask u=rwx,g=,o=
envdir /etc/wal-e.d/env wal-e backup-fetch /var/lib/postgresql/9.1/main/ LATEST

としてbackup-pushしたデータから基本的な構成を復元した後、先ほどの手順に従ってrecovery.confを作成してpostgresqlを再起動したら、wal_pushされs3にアーカイブが残っている部分まで復元できる。

不要なアーカイブログとチェックポイントのクリーンアップ

過去のbackup-pushのデータや、wal-pushで送られたアーカイブログは際限なく溜まっていく。S3なのでこれらのファイルを削除しないという方針でいいかもしれないが、DBを復元する際に必要のない、直前のbackup-pushより前のものは削除してしまっても問題ない。

これを行うためには、以下のコマンドを叩けば良い。

envdir /etc/wal-e.d/env wal-e backup-list | tail -n1 | cut -f1 | xargs envdir /etc/wal-e.d/env wal-e delete --confirm before

もう少し慎重に、例えば、3つ前まで残しておきたいというときは、tail -n1tail -n3 | head -n1に変えればよい。

ハマったポイント

設定に書くときは、wal-e/usr/local/bin/wal-eにしないとダメだったという話。エラーから検索してたどり着く人もいるかもと思って書いておく。

NOTICE:  pg_stop_backup cleanup done, waiting for required WAL segments to be archived
WARNING:  pg_stop_backup still waiting for all required WAL segments to be archived (60 seconds elapsed)
HINT:  Check that your archive_command is executing properly.  pg_stop_backup can be canceled safely, but the database backup will not be usable without all the WAL segments.
WARNING:  pg_stop_backup still waiting for all required WAL segments to be archived (120 seconds elapsed)
HINT:  Check that your archive_command is executing properly.  pg_stop_backup can be canceled safely, but the database backup will not be usable without all the WAL segments.

これは調べても、ディスク容量が足りないことやpermissionの設定が間違っているのではといった情報しか出てこないのだが、どれも当てはまらなかった。ここで、走らせるarchive_command

archive_command = 'date >> test.txt && echo %p >> test.txt && envdir /etc/wal-e.d/env wal-e wal-push %p || echo $? >> test.txt'

とし、/var/lib/postgresql/9.1/main/test.txtを確認することで、エラーが出た時の終了コードが111となっていることがわかり、daemontoolsのenvdirの項目を見ると、envdirはエラーコード111で死ぬことがわかり、原因を特定できた。

実際は以下の様なエラーが出ていたみたい。

envdir: fatal: unable to run wal-e: file does not exist

これで、

envdir /etc/wal-e.d/env wal-e wal-push %p

envdir /etc/wal-e.d/env /usr/local/bin/wal-e wal-push %p

に変えればいいことがわかった。

bashrc的なものはshを読み込んだ時しか動かないので、手元で走らせても動くけど、postgresが走らせるときには動かないみたいなことが起こるんだなと思った。気づけば当たり前なんだけど・・・。

17
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
14