いいか、よく聴いてくれ。Redisを「ただの速いKVS」だと思って運用しているうちは、いつか必ず本番環境で火を吹くことになる。特にAOF(Append Only File)の永続化メカニズム、その中でも「リライト(Rewrite)」の制御を甘く見ているエンジニアが多すぎる。
今日は、ドキュメントの表面をなぞるだけでは決して到達できない、「AOFリライトの予約状態」と、その裏に隠されたリソース管理の真髄について話をしよう。
—
1. 「AOFリライト」は単なるファイル圧縮ではない
まず、認識を正そう。AOFリライトは、肥大化したAOFファイルを「再構成」するプロセスだ。しかし、その実態は「現在のメモリ上のデータセットを、最短のコマンド形式で書き出す重厚なバックグラウンド処理」である。
ここで重要なのは、Redisがシングルスレッド(メインイベントループ)を維持しながら、どうやってこの重い処理をこなすかだ。Redisは `fork()` を呼び出し、子プロセスにその重責を担わせる。この「子プロセスが動いているか」、あるいは「動こうと列に並んでいるか」を正確に把握せずに、システムを設計するのは無謀と言わざるを得ない。
2. インスツルメンテーション:`INFO persistence` を解読せよ
現場でトラブルが発生した際、真っ先に確認すべきは `INFO persistence` コマンドの結果だ。ここには、AOFリライトの「現在進行形」と「未来の予約」が刻まれている。
redis-cli での状態確認
127.0.0.1:6379> INFO persistence
…
aof_rewrite_in_progress:0 # 1なら現在リライト中。子プロセスが稼働している
aof_rewrite_scheduled:0 # 1ならリライトが「予約」されている
aof_last_rewrite_time_sec:12 # 直近のリライトにかかった時間。これを知らずにタイムアウト設計はできない
…
aof_rewrite_in_progress: 進行中の戦い
これが `1` のとき、OSレベルでは Copy-on-Write(CoW)が発生している。メインプロセスが書き込みを受信するたびに、メモリページのコピーが発生し、メモリ消費量が急増する可能性がある。この状態でさらに重いバッチをぶつけるのは、自ら首を絞める行為だ。
aof_rewrite_scheduled: 待機という名の嵐の予兆
これが `1` になるのは、「BGSAVE(RDB作成)が走っている最中に、AOFリライトのトリガーが引かれた」場合だ。RedisはディスクI/Oの競合を避けるため、RDB作成とAOFリライトを同時に行わない。RDBが終わるのを、AOFリライトがじっと待っている状態だ。
3. なぜ「予約状態」を無視してはいけないのか
テクニカルリードとして、君たちに伝えておきたい設計上の急所がある。
それは、「AOFリライトの予約状態を無視して、メンテナンスや高負荷処理を強行してはならない」ということだ。
1. メモリ・バーストの罠: `aof_rewrite_scheduled` が `1` の状態で、さらに大量の書き込みを行うとどうなるか? RDBが終わり、即座にAOFリライトが始まる。その瞬間、メモリ消費はピークに達し、最悪の場合 OOM Killer にメインプロセスが殺される。
2. ディスクI/Oの飽和: リライトはディスクを激しく叩く。予約されているということは、次に巨大なI/Oが控えているということだ。この状態で「今、余裕があるから」と別のバックアップジョブを走らせるような真似は、プロの仕事ではない。
4. 実務的な監視と制御のパターン
では、具体的にどう振る舞うべきか。コードレビューで私が突き返すポイントはここだ。
アンチパターン:無条件な BGREWRITEAOF
負荷を考えず、定期実行スクリプトで叩く
$ redis-cli BGREWRITEAOF
これは危うい。すでに走っているかもしれないし、予約されているかもしれない。
推奨パターン:状態を確認し、戦略的にトリガーする
運用スクリプトやオートスケールロジックに組み込むべきロジックはこうだ。
def safe_trigger_aof_rewrite(redis_client):
info = redis_client.info(“persistence”)
# 1. 既に実行中なら二重に叩く必要はない
if info.get(“aof_rewrite_in_progress”) == 1:
log.info(“AOF rewrite is already in progress. Skipping.”)
return
# 2. 予約中(RDB待ち)なら、静観するのが賢明
if info.get(“aof_rewrite_scheduled”) == 1:
log.warn(“AOF rewrite is scheduled. System might be under I/O load.”)
return
# 3. 実行直後の場合も、インターバルを置くなどの考慮が必要(aof_last_rewrite_time_secを参照)
# 全ての条件をクリアして初めて、リライトを依頼する
redis_client.bgrewriteaof()
log.info(“AOF rewrite triggered successfully.”)
5. 極限のチューニング:`no-appendfsync-on-rewrite`
AOFリライト中のパフォーマンス低下を極限まで抑えたいなら、この設定を知っておくべきだ。
no-appendfsync-on-rewrite yes
これは、「子プロセスがリライト(fsync)している間、メインプロセスでのfsyncを止める」という設定だ。
- メリット: AOFリライト中のディスク競合によるメインプロセスのブロック(レイテンシスパイク)を防げる。
- リスク: この間にクラッシュすると、最大30秒分(デフォルトのLinux設定の場合)のデータが失われる可能性がある。
このトレードオフを論理的に説明し、プロジェクトの許容リスクに合わせて選択できるのが、真のアーキテクトだ。
結論
RedisのAOFリライト予約状態を確認することは、単なるステータスチェックではない。それは、「システムのメモリとI/Oの生存戦略」を確認する行為そのものだ。
- `aof_rewrite_in_progress` を見て、現在のリソース負荷を察しろ。
- `aof_rewrite_scheduled` を見て、次に来る衝撃に備えろ。
- 状況に応じた `no-appendfsync-on-rewrite` の是非を判断しろ。
ドキュメントの「設定項目一覧」を眺める時間は終わりだ。これからは、Redisの内部状態と対話し、その鼓動(イベントループ)を感じながら、堅牢なシステムを組み上げてほしい。
期待しているぞ。
コメント