【テクニカル・上級編】 appendonly設定 – Redis

Redis永続化の深淵:`appendonly yes` が引き起こすI/Oとメモリの物理限界

データベースのアーキテクチャにおいて、永続化とスループットは常に背反するトレードオフの関係にある。
インメモリデータストアの極限的なパフォーマンスを誇るRedisにおいても例外ではない。RDB(Redis Database)スナップショットが持つ「コピーオンライトによるレイテンシの波及」や「障害時のデータ損失リスク」に対する決定的なアンチテーゼとして存在する機能、それがAOF(Append-Only File)である。

その核心である `appendonly yes` という一行。
これを有効にした瞬間、Redisの内部挙動、OSのページキャッシュ、そしてストレージサブシステムとの関係性は劇的に変化する。本稿では、この単純な設定が引き起こす低レイヤのメカニズムと、大規模システムを破綻させないためのアーキテクトの知見を解き明かす。

—

1. `appendonly yes` の本質:トランザクションログの追記とシステムコールの現実

`appendonly yes` を有効化すると、Redisはメモリ上の状態変化をもたらすすべての書き込みコマンドを、RESP(Redis Serialization Protocol)形式でAOFファイルに順次追記(Append)していく。

一見すると単純なシーケンシャルI/Oだが、ここでエンジニアが理解すべきは、アプリケーション層の `write(2)` システムコールと、OSカーネルのファイルシステムキャッシュ、そしてストレージデバイスの物理特性の相互作用である。

[Redis Client] —> (Write Command) —> [Redis Server Memory]
│
(AOF Bufferへ追記)
│
▼
[OS Page Cache]
│
(fsyncポリシーに依存)
│
▼
[Non-Volatile Storage]

fsync ポリシーが握る生死の境界

AOFを有効にするだけでは、データはOSのページキャッシュに留まる。カーネルがクラッシュすればデータは消失する。ここで重要になるのが `appendfsync` の設定だ。

  • `appendfsync always`: すべてのコマンド毎に `fsync(2)` を強制する。データの安全性は最強だが、ディスクのI/O帯域(特にNVMeでさえも)がボトルネックとなり、スループットは数千QPSへと急降下する。
  • `appendfsync no`: `fsync` を一切行わず、OSのカーネルフラッシュ(通常30秒おき等)に委ねる。パフォーマンスはRDB並みに出るが、OSクラッシュ時に最大数秒〜数十秒のデータ損失(RPO)を許容することになる。
  • `appendfsync everysec`: バックグラウンドスレッドで1秒に1回 `fsync` を実行する。スループットと耐久性のバランスを極限まで最適化した、実務におけるデファクトスタンダードである。

—

2. AOF Rewritingの内部メカニズムとフォークの代償

AOFは「変更履歴の蓄積」であるため、運用を続ければファイルサイズは無限に肥大化する。再起動時に数テラバイトのAOFをリプレイするなどナンセンスだ。ここで稼働するのが AOF Rewrite(`BGREWRITEAOF`)である。

Copy-on-Write (CoW) とメモリ倍化の罠

AOFリライトのプロセスは、Redisの真骨頂である `fork(2)` から始まる。

// 概念的なAOFリライトのトリガー
pid_t pid = fork();
if (pid == 0) {
// 子プロセス: 現在のメモリのスナップショットから極小化されたAOFを構築
rewriteAppendOnlyFile(“temp-rewriteaof.aof”);
exit(0);
} else {
// 親プロセス: 通常処理を継続しつつ、差分をAOF Rewrite Bufferに蓄積
}

ここでチーフアーキテクトとして警告しておかねばならない。`fork()` 自体は高速だが、メモリ空間のページテーブル(Page Table)のコピーが発生する。さらに、親プロセスがデータを更新するたびに、LinuxカーネルのCopy-on-Write機構によりメモリページが複製される。

もしRedisインスタンスが物理メモリの80%を占有している状態でAOFリライトが走ると、最悪の場合、親プロセスと子プロセスでメモリ消費が一時的に2倍に膨れ上がり、LinuxのOOM Killer(Out-Of-Memory Killer)によって容赦なくプロセスが刈り取られる。
大規模運用において `vm.overcommit_memory = 1` の設定と、メモリ使用率(`maxmemory`)の厳格なサイジングが必須である所以はここにある。

—

3. Redis 7.0以降のパラダイムシフト:マルチパートAOF

かつて、RedisのAOFは「単一の巨大なファイル」であったため、リライト中のI/Oスパイクやディスク容量の二重確保(旧AOFと新AOFの一時的な共存)が深刻な課題だった。

Redis 7.0で導入されたMulti-part AOF(マルチパートAOF)アーキテクトは、この構造的欠陥を美しく解決した。AOFを以下の3つのファイル群に分割する。

1. Baseファイル: スナップショットベースの基本データ(RDB形式で効率的に保持)
2. Incrファイル: リライト中に発生した差分ログ(追記用)
3. Manifestファイル: これら複数のファイルを管理するメタデータファイル

このアーキテクチャにより、リライト処理は「単なるBaseファイルの再生成」に抽象化され、ディスクI/Oのフットプリントとメモリのオーバーヘッドが劇的に削減された。現代のプロダクション環境において、Redis 7.0以降の採用はもはや選択肢ではなく前提条件である。

—

4. 実戦的チューニング:プロダクション環境における推奨設定

理論を実務に落とし込む。大規模トラフィックを捌くRedisクラスタにおいて、`appendonly yes` を安全に稼働させるための設定指針を提示する。

AOFの有効化
appendonly yes

マルチパートAOF環境下でのベースファイル名
appendfilename “appendonly.aof”
appenddir “appendonlydir”

1秒ごとの同期(堅牢性とパフォーマンスの最適解)
appendfsync everysec

AOFリライト中のfsync抑制
リライト(子プロセス)とディスクI/Oの競合(ディスクのスタック)を防ぐ
no-appendfsync-on-rewrite yes

自動AOFリライトの閾値
前回のサイズから100%増、かつ64MB以上の場合にリライトを自動発動
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

アーキテクトからの最終提言

`appendonly yes` は、単なる「設定フラグ」ではない。それはRedisのメモリ効率、CPU使用率(forkコスト)、そしてストレージI/O帯域のすべてを支配するシステム全体のコントラクトである。

「データ損失を絶対に許さない」というビジネス要件の裏で、何がカーネル空間とユーザー空間で起きているのか。その物理的な挙動を解像度高く把握して初めて、真に高可用で予測可能なインフラストラクチャが構築できる。
Redisの限界を突破したいのであれば、設定ファイルの変更に終始するのではなく、OSカーネルとストレージの鼓動に耳を澄ませるべきだ。

コメント

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