akishin999の日記

調べた事などを書いて行きます。

Redis の永続化について調べた

Redis でのデータの永続化方法について調べたので、忘れないうちにまとめておきます。

調べた時の Redis のバージョンは 2.6.13 です。

スナップショット(RDB)

  • Redis のデフォルトの永続化の仕組み
  • この設定が有効な場合、Redis は定期的にデータベースの内容をディスクに出力する
  • Redis を再起動するとこのファイルからデータが読み込まれ復元される
  • 一定回数の更新 + 一定間隔でディスクにファイル出力
    • ファイル出力タイミングは設定ファイル、CONFIG コマンドで変更可能
    • 無効にもできる
  • 出力は非同期で行われるため、プロセスがクラッシュした場合には前回のスナップショット以降のデータが失われる可能性あり
    • 多少のデータロスを許容できるようなデータならスナップショットのみでもイケそう
  • 手動で実行するには SAVE コマンドまたは BGSAVE コマンドを実行
    • SAVE はサーバをブロックする
    • BGSAVE はバックグラウンド処理
  • BGSAVE は fork するので、書込みが多いシステムだとメモリ使用量が最大で通常時の二倍程度かかる可能性がある
  • ファイル形式はバイナリ
  • ファイルは設定で圧縮も可能
  • バックアップに適している
  • ファイルが壊れているかどうかは redis-check-dump でチェック可能
RDB 関連の設定項目
設定 意味
save RDB ファイルを自動的にディスクに保存するタイミングを設定。複数指定可能
rdbcompressio RDB ファイルをダンプするときに、文字列を圧縮するかどうかを指定
dbfilename RDB ファイルのファイル名を指定
dir RDB ファイルの出力先ディレクトリを指定

追記専用ファイル(Append Only File、AOF)

  • 書き込み操作を全てログファイルに記録していく
  • スナップショットでのデータロスの可能性を許容できない場合はこれ
  • スナップショットと併用した場合、再起動時には追記専用ファイルの方が使用される
  • ファイル出力タイミングは設定で変更可能
    • デフォルトは 1 秒毎
  • スナップショットに比べるとより安全
  • スナップショットと併用可能
    • ドキュメントでは AOF 単体運用は推奨されてないっぽい
  • ファイル形式はテキスト
  • ファイルサイズはどんどん肥大化していくので、定期的に再構成する必要がある
  • 2.2 では手動で BGREWRITEAOF コマンドを実行
  • 2.4 からは自動的に再構成を実行できる
  • BGREWRITEAOF は fork するので、書込みが多いシステムだとメモリ使用量が最大で通常時の二倍程度かかる可能性がある
  • ファイルが壊れているかどうかは redis-check-aof でチェック可能
    • 壊れていた場合には –-fix オプションで修復できる
AOF 関連の設定項目
設定 意味
appendonly 追記専用モードを有効にするかどうかを指定
appendfilename 追記専用ファイルのファイル名を指定
appendfsync fsync を呼び出すタイミングを指定
auto-aof-rewrite-percentage 指定したパーセントを超えた場合に自動的に AOF を再構成する
auto-aof-rewrite-min-size 指定したサイズ以下の場合には自動的に再構成しない
no-appendfsync-on-rewrite yes にすると BGSAVE や BGREWRITEAOF の実行中にメインスレッドからの fsync 呼び出しが行われないようになる
dir AOF ファイルの出力先ディレクトリを指定
BGREWRITEAOF のメモリ使用量について

BGREWRITEAOF がメモリを大量に使ってしまう問題については以下のスライドが参考になりました。

Redisととあるシステム
http://www.slideshare.net/TakehiroTorigaki/redis-12566649

また、公式にも以下のように書かれています。

Redis Administration -- Redis
http://redis.io/topics/admin

If you are using Redis in a very write-heavy application, while saving an RDB file on disk or rewriting the AOF log Redis may use up to 2 times the memory normally used. The additional memory used is proportional to the number of memory pages modified by writes during the saving process, so it is often proportional to the number of keys (or aggregate types items) touched during this time. Make sure to size your memory accordingly.

fork によるバックグラウンドでのファイル出力で発生するので、スナップショット(BGSAVE) 時にも同じ問題があります。
Linux の fork 時のメモリは Copy on Write なので、書込みが多いと実際にコピーされるメモリ量も多くなってしまうという事のようです。

というわけで、永続化を使う場合はどうやらメモリをフルに使い切れないような感じです。

レプリケーション

永続化ではありませんが、サーバ障害によるデータ損失の防止策としても有効なのでついでに。

  • マスタ - スレーブ構成のレプリケーション
  • 1マスタ・複数スレーブは可
  • マルチマスタは不可
  • スレーブのスレーブは可
  • 2.6 からはスレーブはデフォルトで ReadOnly
  • マスタサーバの変更は再起動無しで SLAVEOF コマンドで可能
    • スレーブからマスタへの昇格も同様
  • マスタの書込み負荷の方が高いようなシステムの場合、スナップショットや追記専用ファイルはスレーブでのみ有効にする、といった使い方もできそう
  • レプリケーション開始時にはマスタで BGSAVE 相当の処理が行われる
    • メモリがカツカツだとスレーブ追加できない?
レプリケーション 関連の設定項目
設定 意味
slaveof スレーブとして動作させる場合に、マスタの IP アドレス、ポート番号を指定
repl-ping-slave-period スレーブがマスターに PING を送る間隔を指定
masterauth マスタに requirepass でパスワードが設定されている場合にパスワードを指定
slave-serve-stale-data マスタと接続できなくなった場合等に古い(可能性がある)データをクライアントに返すかどうか
slave-read-only スレーブを読取専用にするかどうか
repl-timeout 大量のマスタデータ受信時のタイムアウト
repl-disable-tcp-nodelay レプリケーション接続にて TCP_NODELAY を無効化するかどうか
slave-priority Sentinel がマスタ昇格するスレーブを選択する際の優先度

用途

これらの機能を実際に使う場合、どの組み合わせが最適なのかは保存するデータの性質によって異なると思います。
個人的には扱えるデータ量がメモリサイズで決まってしまうという事、BGSAVE などを考慮するとそのメモリも使いきれない事、などを考えると、レプリケーション以外はそこまで扱いやすい機能でもないな、という印象を持ちました。
レプリケーションについても、メモリカツカツ状態でのスレーブ追加は試していないのですが、WEB+DB PRESS の特集記事読む限りでは同じ問題が起きそうです。

永続化したいようなデータを Redis に保存する場合、メモリ量には余裕を持つ必要がありそう。
永続化無しで Sharding + レプリケーション、とかが一番スケールし易そうかなー。

参考書籍

こちらの特集記事が非常に勉強になりました。
Redis を導入するなら一読をお勧めします。

参考サイト

Redis Persistence – Redis
http://redis.io/topics/persistence

Replication -- Redis
http://redis.io/topics/replication

追記専用ファイルモード ― redis 2.0.3 documentation
http://redis.shibu.jp/admin/append_only_file.html

スナップショットの設定
http://redis.shibu.jp/admin/config.html#id4