Redisの心臓部を紐解く:AOF書き換え(BGREWRITEAOF)の真実と、本番環境を救う「運用の美学」
Redisを単なる「高速なキーバリューストア」と捉えているなら、それはまだ入り口に立ったに過ぎない。大規模トラフィックを捌くシステムのエンジニアであれば、「永続化層の健全性」こそがシステムの寿命を決めるという事実に気づいているはずだ。
今日は、RedisのAOF(Append Only File)書き換え、すなわち `BGREWRITEAOF` について、教科書には載っていない「現場の知見」を共有する。
—
1. なぜ「Append Only」がボトルネックになるのか
Redisは、発生した更新コマンドをログの末尾に追記していく。これがAOFの基本だ。シンプルだが、ここには致命的な罠がある。
「無駄な追記の蓄積」だ。
例えば、`SET counter 1` から始まり、100万回インクリメントを繰り返すと、AOFファイルには100万行のコマンドが並ぶ。しかし、リカバリ時に本当に必要なのは `SET counter 1000000` という結果の1行だけだ。
肥大化したAOFは、以下の二重苦をもたらす。
1. ディスクの圧迫: 不要な履歴がテラバイト級のログを食いつぶす。
2. リカバリ時間の増大: 再起動時に100万行を再実行するため、サービス復旧までに数分〜数十分を要する。
これを解決するのが `BGREWRITEAOF` だ。
—
2. BGREWRITEAOFの「舞台裏」を理解せよ
このコマンドが実行されるとき、Redis内部では何が起きているのか。ここを理解せずに運用するのは危険だ。
1. 子プロセスのフォーク: メインプロセスはそのままに、子プロセスが生成される。
2. メモリの抽象化(Copy-on-Write): 子プロセスは、フォーク時点のメモリ状態をスナップショットとして保持する。
3. コマンドの再構築: 子プロセスはメモリ内のデータ構造を走査し、それを最小限のコマンドセット(SET, SADD等)に変換して、テンポラリファイルへ書き出す。
4. 追記の同期: 書き換え中もメインプロセスは新しいコマンドを受け取る。これらはメモリ上のバッファに蓄積され、最後に書き換え後のファイルに追記される。
5. ファイルの切り替え: テンポラリファイルが完成した瞬間、アトミックに古いAOFと置き換わる。
注意点: 書き換え実行中、メモリの消費は一時的に跳ね上がる。物理メモリ限界ギリギリで運用している環境では、フォーク時のCopy-on-WriteでOOM Killerに殺されるリスクがある。余剰メモリの確保は、Redis運用の鉄則だ。
—
3. 実務で「刺さる」設計パターンとパラメータチューニング
`redis.conf` のデフォルト設定で満足してはいけない。本番のワークロードに応じたチューニングが、システムの堅牢性を担保する。
書き換えのトリガー設定(重要)
前回の書き換えサイズから100%増加したら、自動でBGREWRITEAOFを実行する
auto-aof-rewrite-percentage 100
ただし、最低でも64MBは超えてから実行する(頻繁な書き換えを防ぐ)
auto-aof-rewrite-min-size 64mb
【エンジニアへの提言】
書き換えの間隔が短すぎると、子プロセスが頻繁に立ち上がりCPU負荷が高まる。逆に長すぎるとファイルが肥大化する。このバランスは「データ更新頻度」と「許容できる復旧時間」のトレードオフだ。
プロフェッショナルな監視術
書き換えの健全性を測るために、以下のメトリクスを必ず監視せよ。
- `aof_rewrite_in_progress`: 書き換えがスタックしていないか。
- `aof_current_size` vs `aof_base_size`: この乖離が大きすぎる場合、自動書き換えが適切にトリガーされているか確認が必要だ。
—
4. 陥りがちなアンチパターン
最後に、コードレビューで必ず指摘する「やってはいけないこと」を記す。
- 書き換え中のストレージI/Oスパイクを無視する:
書き換えはディスクI/Oを激しく消費する。クラウド環境(特にEBSやPersistent Disk)では、書き換えのタイミングがI/O性能の限界に達し、メインプロセスのレスポンスが悪化することがある。「ディスクのIOPS上限」を事前に計算しておくこと。
- 書き換え失敗の放置:
ディスク容量不足で書き換えが失敗した場合、Redisは書き込みを受け付けなくなる可能性がある。`aof_last_bgrewrite_status` が `ok` であることを、監視ツール(Prometheus等)でアラート設定しておくべきだ。
—
結び:エンジニアリングの品格
AOF書き換えは、一見すると「Redisが勝手にやってくれる裏方作業」に見える。しかし、この挙動を掌握し、メモリとI/Oの特性を理解して環境を構成することは、大規模システムを支えるアーキテクトとしての矜持そのものだ。
「とりあえず動く」から一歩先へ進み、「いかなる状況でも最短で復旧し、パフォーマンスを維持する」ための設計を追求してほしい。
君たちが書くそのコードが、システムの背骨となるのだから。
コメント