Redisの死地を避ける:AOFリライトとfsyncの「黄金律」
Redisを単なる「高速なKVS」と捉えているなら、それはまだ入り口に過ぎない。大規模トラフィックを捌く現場において、Redisの真価は「いかにクラッシュさせず、かつレイテンシのスパイクを許さないか」という極限のトレードオフを制御するエンジニアリングにある。
今回は、多くのエンジニアが「デフォルト設定」で放置し、後にシステムを瀕死に追い込むAOFリライト時のfsync戦略について、アーキテクトの視点から深掘りする。
—
1. なぜ「AOFリライト」は悪魔になり得るのか
AOF(Append Only File)は、すべての書き込み操作をログとして記録する。しかし、時間が経てばログは肥大化し、再起動時のロード時間が地獄と化す。これを解消するためにRedisは「リライト(BGREWRITEAOF)」を行い、現在のデータセットから最小限のコマンド群を再構築する。
問題は、このリライトがバックグラウンドで行われている最中、親プロセスと子プロセスの双方がI/Oを激しく奪い合う点にある。
特に`no-appendfsync-on-rewrite`の設定を誤ると、リライト中のI/O負荷がディスクI/Oのボトルネックを突き抜け、Redis全体のレスポンスを数秒間フリーズさせる「Stop-the-world」を引き起こすことになる。
2. 極限設定:`no-appendfsync-on-rewrite` の真実
Redisの設定ファイルにあるこのパラメータは、一見すると些細なものに見えるが、システムの生存戦略を左右する。
デフォルトは no
これを yes にすると、AOFリライト中は fsync をスキップする
no-appendfsync-on-rewrite yes
なぜ `yes` にすべきなのか?
現代のNVMe SSDであっても、高負荷時のfsyncはレイテンシのスパイクを生む。`no-appendfsync-on-rewrite yes` を設定すると、リライト中、メインスレッド側のfsyncが一時停止される。
- メリット: リライトによるI/O負荷と、通常書き込みのfsyncが競合しないため、レイテンシのスパイクが劇的に抑制される。
- リスク: リライト中にOSがクラッシュした場合、最大で30秒分の書き込みデータが消失する可能性がある。
アーキテクトの助言:
「データ消失を許容できない」という声が飛んできそうだが、高可用性を重視するなら、Redis単体のfsyncに頼るべきではない。Replicaによる冗長化が前提であれば、書き込みの堅牢性はRedisのfsyncではなく、クラスタの構成で担保すべきだ。
3. 実務で「詰む」ポイント:ディスクI/Oの平滑化
単に設定を切り替えるだけでは不十分だ。ディスクI/Oのスパイクを完全に抑え込むには、以下の設計パターンを意識してほしい。
① `aof-rewrite-incremental-fsync` の活用
リライト中、Redisは書き出したAOFデータを一定量(デフォルト32MB)ごとにfsyncする。これにより、一度に巨大なデータがカーネルのページキャッシュに流れ込み、後に発生する「fsyncの嵐(大規模なI/Oブロッキング)」を避けることができる。
32MBごとにfsyncすることで、I/Oを小分けにして平滑化する
aof-rewrite-incremental-fsync yes
② ディスクの物理分離
Redisのデータディレクトリと、ログや他のプロセスが使用するディスクは、物理的あるいは論理的に分離せよ。特にクラウド環境では、ディスクI/Oの上限(IOPS/スループット)が設定されている。リライトがスループット制限を食いつぶすと、アプリケーションの読み書きすべてが停滞する。
4. 設計レビューのためのチェックリスト
君たちが現場でRedisを設計する際、以下の項目をクリアしているか自問してほしい。
- [ ] fsyncの頻度は適切か?: `appendfsync everysec` が標準だが、なぜそれを選んだのか説明できるか?(`always` は論外である)
- [ ] リライト中のI/O負荷を考慮したか?: `no-appendfsync-on-rewrite yes` にした場合の「最大30秒のデータ欠損」というリスクを、ビジネス要件として許容したか?
- [ ] 書き込み負荷は平滑化されているか?: 急激なアクセス増でリライトが頻発しないよう、`auto-aof-rewrite-percentage`(通常100%)を適切に調整したか?
- [ ] 監視は万全か?: `aof_delayed_fsync` メトリクスを監視し、fsyncがボトルネックになっていないか可視化しているか?
終わりに:アーキテクトからのメッセージ
Redisは魔法の箱ではない。メモリという高速な領域と、ディスクという低速な領域を仲介する、非常に繊細な実装の塊だ。
設定値を「なんとなく」で決めるのではなく、その設定が「どのリソースを犠牲にして、何を優先しているのか」を数式のように理解してほしい。 高いパフォーマンスは、こうした地味なI/Oの平滑化と、リスクのトレードオフを言語化できるエンジニアの頭の中にしか存在しない。
次は、Redisのメモリデフラグ(Active Defrag)の挙動について、同じレベルで掘り下げていくとしよう。健闘を祈る。
コメント