【テクニカル・上級編】 永続化レイテンシ監視 – Redis

Redis永続化レイテンシの極限監視:I/Oの呪縛を断ち切るアーキテクチャ

データベースのレイテンシ最適化において、最も厄介で、最も見落とされがちなボトルネックは「ディスクI/O」だ。インメモリデータベースであるRedisをどれだけ綺麗にチューニングしようとも、ひとたびRDB(AOF/RDB)の永続化が絡むと、物理ディスクの現実が牙をむく。

特に、`fsync` システムコールが引き起こすバックグラウンドスレッドのブロックや、それに伴うメインイベントループのレイテンシスパイクは、高ス負荷なプロダクション環境において致命傷となり得る。

本稿では、Redisの内部メカニズム、特にオペレーティングシステムのカーネル挙動と `Latency Monitor` を完全に同期させ、I/Oレイテンシの呪縛を極限まで暴く手法を解説する。

—

1. 永続化レイテンシの根源:なぜRedisは「止まる」のか

Redisは基本的にシングルスレッドのイベントループ(正確にはネットワークI/Oやコマンド処理)で動作している。しかし、永続化(RDBの `fork()` や AOFの `fsync()`)は別プロセス、あるいはバックグラウンドスレッド(BIOスレッド)で実行される。

ここで問題になるのは、ハードウェアとOSカーネルの物理的限界である。

[Main Thread] —> (Command Execution)
|
v (AOF Rewrite / fsync)
[Background I/O (BIO) Thread] —> write() —> Page Cache
|
v (Kernel flush / fsync)
[Physical Disk / NVMe]
^
| (ここでカーネルがブロック)

1. `fsync()` の同期ブロック:
AOFの `appendfsync everysec` や `always` では、バックグラウンドスレッドが `fsync()` を呼び出してページキャッシュをストレージにフラッシュする。この時、ストレージコントローラやNANDフラッシュのキューが飽和していると、`fsync()` 自体が数ミリ秒〜数百ミリ秒単位でブロックされる。
2. `fork()` による Copy-on-Write (COW) のメモリページ枯渇:
RDBスナップショットを生成するための `fork()` 自体は高速だが、巨大なデータセット(例: 100GB)を持つインスタンスでは、Page Tableの複製とCOWに伴うメモリ解放時に親プロセス(メインスレッド)が数秒単位で巻き込まれ、レイテンシが跳ね上がる。

これらを「感覚」ではなく「メトリクス」として正確に捉える唯一の手段が、Redisの Latency Monitor である。

—

2. Latency Monitorの内部アーキテクチャ

Redisのレイテンシモニターは、あらかじめ設定された閾値(ミリ秒)を超える処理時間を検知した場合、そのイベントの発生時刻、継続時間、およびスタックトレースやイベントの種類をリングバッファに記録する。

この仕組みの美しさは、パフォーマンスオーバーヘッドが極限まで低いことにある。CPUのサイクルカウンタや高精度タイマー(`monotonic clock`)を利用し、イベントループの各フェーズの差分を計測しているため、常時有効にしておいても実用上のペナルティはほぼゼロだ。

監視すべき主要な永続化関連イベント

Latency Monitorの出力において、以下のイベント名が出現した瞬間、インフラストラクチャあるいは設定に異常が発生していると断定して良い。

  • `fast-fsync`: バックグラウンドでの `fsync` が遅延している。
  • `aof-rewrite-diff-write`: AOF書き換え完了時の差分データ書き込みに時間がかかっている。
  • `rdb-cow-del`: RDBのフォーク後、COWによるメモリ解放に時間がかかっている。
  • `active-defrag-cpu`: メモリ断片化解消処理がI/OやCPUを圧迫している。

—

3. 実践:Latency Monitorの設定と深層解析

まずは、プロダクション環境における最低限のガードレールとして、レイテンシモニターの閾値を設定する。デフォルトでは無効(`0`)になっているため、例えば `10ms` 以上のスパイクをすべて記録するように指定する。

10ミリ秒(10000マイクロ秒)を超えるイベントをすべて記録の対象とする
CONFIG SET latency-monitor-threshold 10

データの回収と解析

イベントが発生したら、`LATENCY LATEST` や `LATENCY HISTOGRAM` を用いて詳細なプロファイルを取得する。

127.0.0.1:6379> LATENCY LATEST
1) 1) “fast-fsync”
2) (integer) 1672 # 最後に発生した時刻からの経過秒数
3) (integer) 48 # 継続時間(ミリ秒)! 48msのブロックが発生している
4) (integer) 2 # イベントの発生回数

この `fast-fsync` が `48ms` 記録されたという事実は、「バックグラウンドでディスクへのフラッシュが完了するまでの間、OSのI/Oサブシステムが極限まで詰まっていた」 ことを意味する。

さらに深く掘り下げるには、`LATENCY DOCTOR` コマンドを使用する。Redisのチーフアーキテクト的視点からも、このコマンドが自動生成する診断レポートは非常に優秀だ。

127.0.0.1:6379> LATENCY DOCTOR

  • Das RDB snapshotting execution time is 1 seconds…
  • fsync() execution time has been over 10 milliseconds for 2 times.

The disk is slow and cannot handle the traffic.
Check your hardware / RAID controller battery backup.

—

4. カーネルとハードウェアの限界を突破する処方箋

Latency Monitorによって「どこで詰まっているか」が特定できたら、次はレイテンシの根絶だ。単にRedisの設定を変えるだけでは解決しない。OSカーネルとストレージのレイヤーに踏み込む必要がある。

① AOFの `no-appendfsync-on-rewrite` の罠

AOFの `everysec` を利用している場合、`BGSAVE` や `BGREWRITEAOF` が実行されると、親プロセス側で重いディスクI/O(fsync)が発生する可能性がある。これを防ぐために以下の設定を入れることがある。

no-appendfsync-on-rewrite yes

しかし、この設定は「書き換え中のデータロスリスクを許容する」トレードオフである。障害時に最大30秒分のデータが消失するリスクをアーキテクトとして受け入れられるか、ビジネス要件と厳密に突き合わせる必要がある。

② ストレージI/Oキューの深度(IOPSとLatencyの物理法則)

NVMe SSDを使用している場合でも、RAIDコントローラのキャッシュポリシー(Write Back / Write Through)や、LinuxカーネルのI/Oスケジューラ(`none` または `bfq` / `mq-deadline`)の設定が不適切だと、単一の `fsync` が数ミクロン秒ではなく数十ミリ秒のスパイクを引き起こす。

  • Linux I/Oスケジューラの最適化: NVMe環境では、I/Oスケジューラを `none` (または `kyber`)に設定し、カーネルの無駄なオーバーヘッドを排除する。

echo none > /sys/block/nvme0n1/queue/scheduler

  • Dirty Pageのフラッシュ制御: `vm.dirty_background_ratio` と `vm.dirty_ratio` のチューニングにより、メモリ上のダーティページがストレージへフラッシュされる際の「一気に書き込んで詰まる現象(バースト)」を防ぐ。

—

5. 究極の選択:永続化を捨てるか、スケールするか

もし、Latency Monitorが示す `fast-fsync` のレイテンシが、ハードウェアの限界(これ以上速いSSDが存在しない)に達している場合、アーキテクトに残された選択肢は以下の3つに絞られる。

1. 永続化の完全オフ(Pure In-Memory Cache):
Redisを純粋なキャッシュ層として割り切り、RDB/AOFを完全に無効化する。耐久性はRDBのバックアップではなく、下流の永続化ストレージ(AuroraやDynamoDBなど)からのウォームアップに委ねる。
2. 専用の非同期レプリカ(Offloaded Persistence):
プライマリノードでは永続化を一切行わず(`save “”`)、読み取り専用のレプリカノード側でRDBスナップショットを生成し、バックアップを取得する。これにより、書き込みパスのレイテンシを完全に保護する。
3. Persistent Memory (PMEM / CXL) の採用:
将来的なハードウェアアプローチとして、NVDIMMやCXL接続のメモリプールを活用し、バイトアドレス可能な永続化を実現する。

—

結言

Latency Monitorは、単なる「エラー発見ツール」ではない。それは、Redisが稼働するハードウェア、OSカーネル、そしてアプリケーションのデータモデルの歪みを正確に映し出す鏡である。

「なぜRedisが遅いのか」と悩むフェーズは、もはや過去のものにすべきだ。Latency Monitorを常時監視の網の目に組み込み、ミリ秒単位のノイズを見逃さず、システム全体のレイテンシバジェットを支配せよ。それこそが、真のインメモリ・アーキテクトの仕事である。

コメント

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