KEYSコマンドの呪縛:Redisの心臓部を停止させる「静かなる爆弾」
Redisを運用する上で、初心者が最初に犯す過ちであり、熟練者が最も忌み嫌うコマンドがある。それが `KEYS` だ。
「本番環境で使うな」という定型句は、多くのドキュメントで繰り返されている。だが、なぜそれが「システムを物理的に殺す」のか。単なる「負荷が高まる」という曖昧な表現では語り尽くせない、Redisの内部アーキテクチャの根幹に触れる話をしよう。
—
1. O(N) の深淵:Redisのシングルスレッドモデルとブロッキング
Redisがなぜこれほどまでに高速なのか。それは、メインのコマンド処理系がシングルスレッドで動くという、極めて純粋な設計思想にある。
`KEYS` コマンドが実行されると、Redisはバックグラウンドで処理を行わない。メインループそのものを完全に占有し、データベース内の全キーをスキャンし始める。
内部メカニズムの解剖
Redisのデータ構造は、メインとなる `dict`(ハッシュテーブル)に格納されている。`KEYS` が呼ばれると、Redisは以下の手順を強制実行する。
1. データベースの全スロットを反復走査: ハッシュテーブルの各バケットを舐め尽くす。
2. パターンマッチング: 文字列比較(glob形式)を全キーに対して逐次実行する。
3. 結果のバッファリング: マッチしたキーをメモリ上のクライアント出力バッファに詰め込む。
この間、Redisは他のすべてのリクエストを処理できない。たとえ `GET` や `SET` というミリ秒単位の処理であっても、`KEYS` が数百万キーをスキャンしている間、それらはキューで待機させられる。これが、レイテンシのスパイク(あるいはタイムアウトの連鎖)を引き起こす正体だ。
2. なぜ「スキャン」ではなく「KEYS」が凶悪なのか
多くのエンジニアは「メモリが足りているなら大丈夫だろう」と錯覚する。しかし、問題はCPUやメモリの枯渇だけではない。
「クライアント出力バッファの暴走」を忘れてはならない。
大量のキーがマッチした場合、Redisはその膨大なリストを一度に返そうとする。ネットワーク帯域の飽和だけでなく、Redisのメモリ管理層における出力バッファの肥大化を招き、最悪の場合、Redisが OOM (Out Of Memory) 殺しに遭うか、クライアント接続が強制切断される。
3. 解の提示:SCANコマンドと「反復の哲学」
もし君が本番環境でキーを探索しなければならない状況に陥ったなら、即座に `KEYS` を忘れ、`SCAN` を採用せよ。
`SCAN` は、カーソルベースのイテレータだ。これは「アトミックな全走査」という幻想を捨て、「分割統治」を選択するということだ。
カーソル0から開始し、マッチしたキーを一度に100個ずつ取得する
実行するたびに次のカーソル位置が返されるため、処理を中断・再開できる
SCAN 0 MATCH “user:session:” COUNT 100
なぜSCANが「真の解」なのか
- 非ブロッキング性: 一度の操作が軽量であり、合間に他のコマンドを挟み込む余地がある。
- 整合性の担保: 厳密なスナップショットではないが、反復中に発生したキーの変更に対して、Redisは整合性を保つための「ハッシュスロットの再スキャン」を内部的に最適化している。
4. アーキテクトとしての提言:そもそも「探索」を不要にせよ
ここまで `KEYS` や `SCAN` の話をしてきたが、真のアーキテクトであれば、「そもそもキーを検索する必要がある設計」そのものを疑え。
Redisはキーバリューストアであり、検索エンジンではない。もし `KEYS` でキーを列挙しなければならない状況があるなら、それはデータモデリングの敗北だ。
- Set構造によるインデックス: 検索したい属性をSetに保持し、SINTER(積集合)等で解決する。
- 専用インデックスの維持: キーの命名規則に依存せず、検索用のハッシュやソート済みセット(ZSET)を別個に管理する。
—
結論:技術の「境界線」を見極めろ
`KEYS` は、Redisの内部構造を理解するための良い教材だ。しかし、実務においてそれを使用することは、エンジンを回しながら分解整備を試みるようなものだ。
君が扱うシステムが大規模であればあるほど、その一撃は致命傷になる。
「便利であること」と「安全であること」を混同するな。 道具の仕組みを極限まで理解した者だけが、その道具を「使わない」という高度な選択ができるのだ。
今日のRedis運用において、君のツールボックスから `KEYS` を取り出し、代わりに `SCAN` と「インデックス設計」という武器を入れ直すこと。それが、システムを止めないための唯一の防壁となる。
コメント