【実務・中級編】 AOFリライト予約状態 – Redis

いいか、よく聴いてくれ。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の内部状態と対話し、その鼓動(イベントループ)を感じながら、堅牢なシステムを組み上げてほしい。

期待しているぞ。

コメント

タイトルとURLをコピーしました