【実務・中級編】 監視とメトリクス (INFOコマンド) – Redis

Redisの心臓部を覗き見ろ:`INFO`コマンドが語る真実と、本番障害を防ぐメトリクス監視の極意

システム開発の現場において、Redisは「高速なインメモリキャッシュ」として安易に導入されがちだ。しかし、メモリ管理のメカニズムやシングルスレッドの特性を理解せずに運用すれば、ある日突然のレイテンシースパイクやOOM(Out Of Memory)Killerによるプロセス強制終了という悪夢に見舞われる。

Redisの健康状態を把握し、潜在的なボトルネックを事前に察知するための最も強力な武器、それが `INFO`コマンド だ。

本稿では、単なるメトリクスの列挙ではない。プロのアーキテクチャ設計者が実務の現場で「どこを見ているのか」「どの数値を超えたらアラートを鳴らすべきか」という実践的な知見を、魂を込めて伝授する。

—

1. `INFO`コマンドの構造と全体像

`INFO`コマンドは、Redisサーバーの統計情報や状態をセクションごとにテキスト形式で出力する。

すべてのセクションを一括取得(本番環境では高負荷になるため原則禁止)
$ redis-cli INFO

セクションを指定して取得(実務ではこちらを使うべき)
$ redis-cli INFO memory

出力は `#` で始まるセクション名と、`key:value` のペアで構成される。主要なセクションは以下の通りだ。

  • `server`: RedisのバージョンやOS、プロセスIDなど(静的な情報)
  • `clients`: クライアント接続に関する統計
  • `memory`: メモリ使用量とフラグメンテーションの状況
  • `stats`: コマンド処理数、ヒット率、ネットワークI/Oなどの汎用統計
  • `cpu`: CPU使用率
  • `keyspace`: データベースごとのキー数と有効期限付きキー数

—

2. 命綱となる「主要メトリクス」と現場の閾値

実務の監視において、すべてのメトリクスを見る必要はない。我々が注視すべきは、システムの生死に直結する以下の4つの領域だ。

A. メモリ管理 (`# memory`) — OOMとの闘い

Redis運用において最も恐れるべきはメモリ枯渇だ。以下の指標は常に監視せよ。

  • `used_memory`: Redisがデータ保持のために消費している実バイト数。
  • `used_memory_rss`: OS側から見たRedisプロセスが消費している物理メモリ量(Resident Set Size)。
  • `mem_fragmentation_ratio`: `used_memory_rss / used_memory` の比率。

— INFO memory の出力抜粋例 —
used_memory:1073741824 # 1GB
used_memory_rss:1610612736 # 1.5GB
mem_fragmentation_ratio:1.50 # RSSがメモリ実体より50%大きい

> 🔥 チーフアーキテクトの視点:メモリフラグメンテーション
> `mem_fragmentation_ratio` が `1.5` を超えている場合、OSのメモリ allocator(jemalloc等)レベルで断片化が発生している。逆に `1.0` を下回っている(スワップが発生している)場合は極めて危険だ。
> また、`maxmemory` 設定と `maxmemory-policy`(`allkeys-lru` や `volatile-lru` など)が適切に設計されているかを必ず確認しろ。これがないRedisは、時限爆弾を抱えているのと同義だ。

B. クライアント接続 (`# clients`) — コネクションリークの検知

アプリケーション側のコネクションプール設定ミスや、ゾンビ化したクライアントによるリソース枯渇を見抜く。

  • `connected_clients`: 現在のクライアント接続数。
  • `blocked_clients`: `BLPOP` や `XREAD` などでブロックされているクライアント数。
  • `rejected_connections`: `maxclients` 制限に達したために拒否された接続の累計数。

— INFO clients の出力抜粋例 —
connected_clients:1250
blocked_clients:15
rejected_connections:0

> 🔥 チーフアーキテクトの視点
> `rejected_connections` が `0` より大きい場合、即座にアラートを発報させろ。OSの `ulimit -n`(ファイルディスクリプタ上限)または Redis側の `maxclients` 設定が限界を迎えている証拠だ。アプリケーション側のコネクション切断漏れ(リーク)を疑え。

C. パフォーマンスとヒット率 (`# stats`) — 非効率なクエリの検知

キャッシュとしての効率性、およびRedisのシングルスレッドを圧迫する要因を測定する。

  • `keyspace_hits` / `keyspace_misses`: キャッシュヒット数とミス数。
  • `instantaneous_ops_sec`: 秒間処理コマンド数(QPS)。
  • `expired_keys`: TTLによって自動削除されたキーの総数。
  • `evicted_keys`: メモリ上限(`maxmemory`)到達により強制削除されたキーの総数。

> 🔥 チーフアーキテクトの視点:キャッシュヒット率の計算
> キャッシュヒット率は以下の式で算出する。
> $$\text{Hit Rate} = \frac{\text{keyspace\_hits}}{\text{keyspace\_hits} + \text{keyspace\_misses}}$$
> この値が 95%を下回る ようであれば、キャッシュ戦略そのものが破綻している。DBへのクエリ負荷が落ちていないかを直ちに疑うべきだ。
> また、`evicted_keys` が増加し続けている場合も致命的だ。メモリサイズがデータ量に対して不足しているか、TTL設計が間違っている。

—

3. 堅牢な設計と運用におけるアンチパターン

コードレビューや設計レビューにおいて、私がエンジニアたちによく厳禁しているポイントを共有する。

アンチパターン 1: 本番環境での愚直な `INFO` ポーリング

開発環境のノリで、高頻度(毎秒など)で `INFO` コマンドを叩く監視スクリプトを本番投入してはならない。`INFO` は(一部のセクションを除き)ロックを獲得して内部状態をかき集めるため、高負荷時にこれを連打すると、Redisのシングルスレッドをブロックし、レイテンシーズパイクを引き起こす。

  • 対策: 監視間隔は最低でも10〜30秒に1回にし、必要なセクション(例: `INFO stats` のみ)を指定して取得せよ。

アンチパターン 2: `keyspace` の肥大化とスキャン

`INFO` の末尾にある `keyspace` セクションでは、データベースごとのキー総数が見える。ここに数千万件以上のキーを単一のDBで抱える設計を見かけたら、その設計は即座に差し戻しだ。

  • 対策: キー数が増えることが予期される場合、キーの名前空間を適切に設計し、必要に応じてRedis Clusterによる水平分散を前提とした設計に落とし込め。また、キーの全件走査に `KEYS` コマンドを使う愚行は絶対にするな。必ず `SCAN` コマンドを使え。

—

4. 実務で使える:Pythonによる健全性チェックスクリプト

最後に、実務の現場でCI/CDパイプラインや簡易的なヘルスチェック(Liveness/Readiness Probe)として応用できる、Python(`redis-py`)を用いたメトリクス取得スコードの雛形を提示する。

import redis
import sys

def check_redis_health(host=’localhost’, port=6379, password=None):
try:
# タイムアウトを厳しく設定し、ブロックを防ぐ
client = redis.Redis(host=host, port=port, password=password, socket_timeout=2.0)

# 必要なセクションのみピンポイントで取得
memory_info = client.info(‘memory’)
stats_info = client.info(‘stats’)
clients_info = client.info(‘clients’)

# 1. メモリフラグメンテーションチェック
frag_ratio = memory_info.get(‘mem_fragmentation_ratio’, 1.0)
if frag_ratio > 1.5:
print(f”WARNING: High memory fragmentation ratio: {frag_ratio}”)

# 2. コネクション拒否チェック
rejected = stats_info.get(‘rejected_connections’, 0)
if rejected > 0:
print(f”CRITICAL: Rejected connections detected: {rejected}”)
sys.exit(2)

# 3. キャッシュヒット率の算出
hits = stats_info.get(‘keyspace_hits’, 0)
misses = stats_info.get(‘keyspace_misses’, 0)
total_requests = hits + misses

if total_requests > 0:
hit_rate = (hits / total_requests) 100
print(f”INFO: Cache Hit Rate: {hit_rate:.2f}%”)
if hit_rate < 90.0: print(f"WARNING: Low cache hit rate: {hit_rate:.2f}%") print("OK: Redis is healthy.") sys.exit(0) except redis.ConnectionError as e: print(f"CRITICAL: Failed to connect to Redis: {e}") sys.exit(2) except Exception as e: print(f"ERROR: An unexpected error occurred: {e}") sys.exit(1) if __name__ == '__main__': check_redis_health() ---

結びにかえて

Redisの `INFO` コマンドから得られる情報は、いわば「システムの健康診断の数値」だ。
優れたエンジニアは、障害が起きてから慌ててログを見る素人ではない。日頃からこれらのメトリクスのトレンド(傾向)を監視し、グラフの異変(例:メモリ使用量の緩やかな右肩上がり、コネクション数の不自然なステップ状の上昇)を誰よりも早く察知して手を打つ。

あなたの扱うRedisは、今、健康な状態だろうか?さっそく `redis-cli INFO` を叩いて、その心音を聞いてみるんだ。

コメント

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