【実務・中級編】 永続化レイテンシ監視 – Redis

Redisが「爆速」であることは、もはや業界の前提だ。だが、君たちのシステムで「たまにRedisが数ミリ秒、あるいはそれ以上黙り込む」という事象は起きていないか?

もし心当たりがあるなら、それはRedisが「メモリという聖域」から「ディスクという物理の泥沼」に足を取られている証拠だ。

世界最高峰の現場で私が何度も目にしてきたのは、永続化(AOF/RDB)の設定をデフォルトのまま放置し、不可解なスパイクに頭を抱えるエンジニアたちの姿だ。今日は、RedisのLatency Monitorを武器に、`fsync`やディスクI/Oが引き起こす「一瞬の沈黙」をどう特定し、どうねじ伏せるかを伝授する。

—

1. 物理の壁:なぜ永続化がレイテンシを生むのか

Redisはシングルスレッド(正確にはメインのイベントループがシングル)で動いている。ここが急所だ。

  • AOF (Append Only File): `fsync`を呼び出す際、OSのバッファを物理ディスクにフラッシュする。この処理がブロックされると、メインループが止まる。
  • RDB (Snapshotting): `fork()`を呼び出す際、メモリ量に比例したページテーブルのコピーが発生する。巨大なインスタンスほど、この「一瞬」が長くなる。

これらを「なんとなく遅い」で片付けてはいけない。数値で、時系列で、確実に捉える必要がある。

—

2. Latency Monitorを覚醒させる

Redisには、実行時間の長いオペレーションを記録するLatency Monitorが標準搭載されている。しかし、デフォルトでは無効(0)だ。まずはこれを有効化することからすべてが始まる。

閾値の設定

実務的には、10ms〜100ms程度を閾値にするのが定石だ。ここでは30msを超えるイベントを追跡してみよう。

実行中に動的に有効化(30ミリ秒以上のレイテンシを記録)
CONFIG SET latency-monitor-threshold 30

レイテンシ事象のサマリを確認

設定後、しばらく運用するとデータが溜まる。まずは`LATENCY LATEST`で、直近で何が起きたかを確認する。

redis-cli> LATENCY LATEST
1) 1) “command” # コマンド実行そのものの遅延
2) (integer) 1683456789 # 発生時刻(Unix Epoch)
3) (integer) 45 # レイテンシ(ミリ秒)
4) (integer) 120 # 過去最大のレイテンシ
2) 1) “aof-fsync-always” # fsyncによるブロック
2) (integer) 1683456800
3) (integer) 85
4) (integer) 210

ここで`aof-fsync-always`や`aof-write-pending`、`fork`といったイベントが出てきたら、犯人はディスクI/Oだ。

—

3. 深掘り:`LATENCY GRAPH` と `LATENCY DOCTOR`

特定のイベント、例えば `aof-fsync-always` がいつ頻発しているかを視覚化するには `GRAPH` コマンドを使う。

redis-cli> LATENCY GRAPH aof-fsync-always
aof-fsync-always – high-res time series of latency:
+—————————————————————————-+
| # |
| # |
| # # |
| # # |
|_#_#________________________________________________________________________|
256ms 128ms 64ms 32ms 16ms 8ms 4ms 2ms

このアスキーアートのグラフは、単なる飾りではない。スパイクが周期的に発生しているなら、それはOSの書き込みバッファ(Dirty Ratio)のフラッシュや、RedisのAOF Rewriteのタイミングと同期している可能性が高い。

さらに、Redisに「診断」を仰ぐこともできる。

redis-cli> LATENCY DOCTOR

これは、現在の統計に基づいたアドバイスを吐き出す。
「AOFの書き込みで遅延が出ているようだ。`no-appendfsync-on-rewrite`を検討しろ」 といった、アーキテクトの視点に近い示唆を与えてくれる。

—

4. 堅牢な設計パターンの極意

レイテンシを特定したら、次は「設計」で殺す。

① `no-appendfsync-on-rewrite` の戦略的採用

BGSAVEやBGREWRITEAOFが走っている最中は、大量のディスクI/Oが発生する。この時に`fsync`を並行して行うと、ディスクのヘッド争奪戦(またはSSDの書き込みキュー待ち)でメインループが確実に止まる。

AOF書き換え中はfsyncをスキップする
no-appendfsync-on-rewrite yes

トレードオフ: この設定を `yes` にすると、書き換え中の数秒〜数十秒の間にクラッシュした場合、その間のデータは失われる。だが、可用性と低レイテンシを最優先するシステムなら、これは「飲むべきリスク」だ。

② AOF Rewriteのインクリメンタルなfsync

最新のRedisなら、以下の設定は必ずチェックしておけ。

AOF書き換え時に一気にfsyncせず、32KBごとに少しずつ流す
aof-rewrite-incremental-fsync yes

これを `yes` にすることで、OSのページキャッシュが巨大な「書き込みの壁」になるのを防ぐことができる。

③ カーネルパラメータの調整(Transparent Huge Pages)

Redisエンジニアなら常識だが、`THP (Transparent Huge Pages)` は永続化の天敵だ。`fork()` 時のメモリコピー負荷を劇的に増大させる。

実行中のサーバーで即座に無効化する(必須)
echo never > /sys/kernel/mm/transparent_hugepage/enabled

—

5. チーフアーキテクトの視点:監視を「点」から「線」へ

Latency Monitorは強力だが、Redis内部の視点に過ぎない。
実務で勝つためには、以下の3点を組み合わせた「多角的監視」を構築せよ。

1. Redis Latency Monitor: 内部的なイベント(fsync, fork)をミリ秒単位で捉える。
2. `INFO persistence`: `rdb_last_bgsave_time_sec` や `aof_last_write_status` を監視し、傾向の変化を掴む。
3. OSレベルの `iostat`: `await`(I/O待ち時間)を監視し、ディスクそのものの劣化や、隣接するプロセスの影響を排除する。

結論

Redisのパフォーマンスチューニングは、単なる「設定値の調整」ではない。それは「メモリの速度を維持するために、いかにディスクの鈍重さを隠蔽するか」という抽象化の戦いだ。

`LATENCY` コマンドを叩き、グラフを読み解き、カーネルの挙動までを支配下に置け。
一瞬の遅延を「誤差」として見過ごすか、システムの「悲鳴」として捉えて設計を磨き上げるか。その差が、一流のエンジニアを分かつ。

君のRedisが、常に「静寂なる高速」を保つことを期待している。

コメント

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