こんにちは、鈴木です。
Redis におけるバックアップとリストアについて調べました。
データを永続化する方法については「Redisにおけるデータの永続化」で調べました。
RDB ファイルのバックアップ
RDB ファイルでのバックアップ手順は以下のようになると思います。
- BGSAVE コマンドを実行する(非同期での RDB ファイルの生成が開始される)。
- RDB ファイルの生成が完了するまで待機する(完了したかどうかは、LASTSAVE コマンドの結果が変化したことや、RDB ファイルの i-node 番号が変化したことで判別可能です)。
- (redis-check-dump で生成された RDB ファイルに問題が無いことを確認する。)
- RDB ファイルをコピーする(別サーバなど Redis が動作するサーバがクラッシュしても安全な場所に保管する)。
上記を一日一回など、定期的に実行します。
RDB ファイルはアトミックに変更されるので、単純にコピーすれば OK
RDB ファイルについて知っておくべきことは、それが「アトミックに変更される」ということです。
具体的には、
- 一時ファイルにデータベースの内容を出力する。
- 一時ファイルへの出力が完了すると、本来保存すべきファイル名にリネームする。
という手順で行われます。
つまり、RDB ファイルが中途半端な状態(出力中の状態)にはならないため、単純にファイルをコピーするだけでバックアップすることができます。
バックアップしたファイルは、別サーバに転送するなど、安全な場所に保存します。
RDB ファイルの生成: save ディレクティブ
RDB ファイルを生成するには、
- save ディレクティブで保存するタイミングを指定する
- SAVE コマンドを実行する
- BGSAVE コマンドを実行する
の 3 通りあります。
save ディレクティブは「Redisにおけるデータの永続化」で説明しましたが、
1 |
save <seconds> <changes> |
という形式で RDB ファイルを書き出すタイミングを指定することができます。
RDB ファイルの生成: SAVE, BGSAVE コマンド
SAVE コマンドは、コマンドを実行した時点で RDB ファイルを生成します。BGSAVE コマンドも似ていますが、こちらは非同期で処理が実行されます。
SAVE コマンドは処理が完了するまで他の処理が行えませんので、バックアップ時には BGSAVE を用いたほうが良いでしょう。
BGSAVE はプロセスを fork して、生成された子プロセスが RDB ファイルの生成を行うため、サーバ本体はリクエストを処理し続けることができます。
定期的なバックアップを行うときは、BGSAVE で RDB ファイルに出力してから、RDB ファイルをコピーします。(save ディレクティブで短い間隔を指定している場合は省略する選択もあります。)
redis-check-dump
Redis には redis-check-dump というコマンドラインツールが付属しています。
使い方は以下の通りで、引数で指定された RDB ファイルに問題が無いことを確認するためのツールです。
1 |
redis-check-dump <dump.rdb> |
試しに使用してみます。
正常な RDB ファイルでは以下のような出力が得られました。コマンドのステータスコードは 0 です。
1 2 3 4 5 |
$ redis-check-dump dump.rdb ==== Processed 6 valid opcodes (in 35 bytes) =================================== CRC64 checksum is OK $ echo $? 0 |
破損したファイルでは以下の出力でした。コマンドのステータスコードは 0 でした。ステータスコードだけで RDB ファイルが破損しているかどうか判別することができないので、注意が必要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ redis-check-dump corrupted.rdb ==== Processed 1 valid opcodes (in 2 bytes) ==================================== ==== Error trace (STRING: fga?) ================================================ 0x00000015 - Followed by invalid type 0x0000000b - Error for type STRING ==== Skipped 7 bytes (resuming at 0x00000012) ================================== ==== Processed 3 valid opcodes (in 24 bytes) =================================== ==== Error trace (EOF) ========================================================= 0x0000002a - Unexpected EOF ==== Processed 0 valid opcodes (in 0 bytes) ==================================== ==== Error trace =============================================================== 0x0000002c - Expected EOF, got Total unprocessable opcodes: 3 $ echo $? 0 |
今度はヘッダを破損した RDB ファイルを試すと、以下の出力が得られました(ステータスコードは 1)。
1 2 3 4 |
$ redis-check-dump corrupted.rdb Wrong signature in header $ echo $? 1 |
全く関係のないテキストファイルを指定したところ、次のような出力でした(ステータスコードは 1)。
1 2 3 4 |
$ redis-check-dump non-rdb.txt Cannot read header $ echo $? 1 |
まとめ
RDB ファイルのバックアップについて調べました。ポイントをまとめると、
- RDB ファイルはアトミックに更新されるので、単純にファイルをコピーすれば良い。
- SAVE コマンドよりも BGSAVE コマンドを使用する(SAVE コマンドを使用すると、処理が完了するまでサーバは他の処理を行わないため)。
- redis-check-dump コマンドで RDB ファイルの破損チェックが可能(スクリプトで処理するときは、コマンドのステータスコードだけ判定できないので注意)。
といった具合でした。