Redisのメモリリークとスパイクをトラブルシューティングするための4つの必須戦略

メモリリークや突然のスパイクはRedisのパフォーマンスを低下させる可能性があります。このエキスパートガイドでは、メモリ消費を積極的に管理しトラブルシューティングするための4つの必須戦略を提供します。`INFO`および`MEMORY USAGE`コマンドを活用した詳細な診断、効果的な`maxmemory`エビクションポリシーの実装、予期しない成長を引き起こす巨大キーの特定と削除、アクティブデフラグメンテーションを使用したシステムレベルの断片化問題の解決方法を学びます。これらの実証済みの実用的なテクニックを使用して、キャッシュのパフォーマンスを安定させ、インメモリデータストアの信頼性を確保します。

Redisのメモリリークとスパイクをトラブルシューティングするための4つの必須戦略

Redisはインメモリデータストアであるため、メモリの問題はすぐに現れます。TTL処理の小さなミス、1つの巨大なリスト、または空きRAMがないホストでのバックグラウンド保存は、レイテンシ、書き込みエラー、エビクション、スワッピング、またはオペレーティングシステムによるRedisプロセスの強制終了につながる可能性があります。

最初に役立つ習慣は、すべてのメモリ増加をリークと呼ぶのをやめることです。真のRedisリークはまれです。ほとんどのインシデントは、実際のデータ増加、アロケータの断片化、または永続化中の一時的なコピーオンライトオーバーヘッドの3つのうちの1つです。ダッシュボードでは似ているように見えますが、修正方法はまったく異なります。

used_memoryが上昇し続ける場合、アプリケーションはおそらく予想よりも多くのデータを保存しています。used_memoryは安定しているがused_memory_rssが跳ね上がる場合、断片化、フォークされたバックグラウンド作業、またはオペレーティングシステムを調べてください。トラフィックスパイク中に両方が上昇し、その後決して低下しない場合は、TTL、エビクションポリシー、および大きなキーを確認してください。

戦略1:使用状況と断片化メトリクスの詳細な監視

メモリ問題を診断する最初のステップは、ベースラインを確立し、Redisがメモリ使用量をどのように報告しているかを理解することです。標準のINFO memoryコマンドは、データによって使用されるメモリとオペレーティングシステムによって使用されるメモリを区別する重要なメトリクスを提供します。

診断のための主要なメトリクス

スパイクが発生した場合、INFO memoryからこれらのメトリクスをすぐに確認してください。

  1. used_memory:Redisがデータと内部構造に割り当てたメモリ。
  2. used_memory_dataset:実際のデータセットによって使用されるメモリ(一部のオーバーヘッドを除く)。
  3. used_memory_rss:オペレーティングシステムがRedisプロセスに割り当てた常駐メモリ。
  4. mem_fragmentation_ratio:RSSと割り当てられたメモリの大まかな比較。手がかりとして扱い、断定しないでください。
# 基本的なメモリ統計を確認
redis-cli INFO memory

# サンプル出力スニペット
# used_memory:1073741824 			# 1 GBのデータ
# used_memory_rss:1509949440 		# RAM内の約1.5 GB
# mem_fragmentation_ratio:1.40625 	# RSSはused_memoryより約40%高い

断片化比率の解釈

比率が1.0に近い場合は通常健全です。1.5を超える比率は、特にRSSがホストを脅かすほど高い場合、調査する価値があります。1.0未満の比率は自動的にスワッピングを証明するものではありません。測定のエッジケース、共有メモリアカウンティング、または非常に小さなデータセットが原因で発生する可能性があります。vmstattopsar、または監視システムを使用して、OSのスワップメトリクスを直接確認してください。

used_memoryがフラットであるにもかかわらず、BGSAVEまたはBGREWRITEAOF中にRSSがスパイクする場合、コピーオンライトが原因である可能性があります。子プロセスは永続化ファイルを書き込んでいる間、親プロセスは書き込みを処理し続けます。親によって変更されたページはコピーする必要がある場合があり、メモリプレッシャーが一時的に増加します。

戦略2:堅牢なエビクションポリシーの実装

無制限の成長は、Redisで認識されるメモリ「リーク」の最も頻繁な原因です。インスタンスがキャッシュとして使用される場合、maxmemoryディレクティブによって強制される、メモリ使用量の定義された上限が必要です。

maxmemoryが設定されていない場合、Redisはホストがプレッシャーを受けるまでメモリを割り当て続ける可能性があります。専用のRedisボックスでは、カーネルがRedisを強制終了する可能性があります。コンテナ内では、コンテナランタイムがより早く強制終了する可能性があります。

maxmemoryの設定とポリシーの選択

redis.confまたはCONFIG SETを使用して、最大メモリ制限を指定します。

# 最大メモリを4 GBに設定。Redisのオーバーヘッド、フォークされた子プロセス、
# OSページキャッシュ、および他のプロセスのために余裕を残す。
CONFIG SET maxmemory 4gb

# エビクションポリシーを設定
# allkeys-lru:データセット*全体*から最も最近使用されていないキーをエビクション
CONFIG SET maxmemory-policy allkeys-lru
ポリシー名 説明 ユースケース
noeviction デフォルト。メモリ制限に達すると書き込みコマンドでエラーを返す。 データ損失が許容されないデータベース。
allkeys-lru 有効期限に関係なく、最も最近使用されていないキーをエビクション。 汎用キャッシング。
volatile-lru 有効期限が設定されているキーのみの中で、最も最近使用されていないキーをエビクション。 混合ユースケース(永続化データ+キャッシュデータ)。
allkeys-random 制限に達したときにランダムなキーをエビクション。 シンプルなセッションストア、またはアクセスパターンが予測不可能な場合。

純粋なキャッシュの場合、allkeys-lruまたはallkeys-lfuが適切な出発点となることがよくあります。一部のキーのみが破棄可能な混合Redisインスタンスの場合、volatile-lruまたは他のvolatile-*ポリシーの方が安全かもしれませんが、それはすべてのキャッシュキーに有効期限がある場合に限ります。危険な設定は、noeviction、TTLの規律なし、メモリがフルになる前のアラートなしのキャッシュです。

戦略3:大きなキーのスパイクの診断と削減

問題はキーの数ではない場合があります。境界なく成長した1つのキーが問題です。トリミングされないユーザーフィードリスト、これまでに見られたすべてのイベントのソートセット、またはセッションフィールドのダンプグラウンドとして使用されるハッシュなどです。

redis-cli --bigkeysの使用

redis-cli --bigkeysユーティリティはキースペースをスキャンし、タイプと要素数ごとに大きなキーを報告します。正確なバイトサイズを測定するわけではなく、ビジーな本番インスタンスに負荷を追加する可能性があるため、可能な場合はレプリカに対して慎重に実行してください。

# bigkeys分析を実行
redis-cli --bigkeys

# サンプル出力(巨大なリストを特定)
---------- サマリー ----------
...
[5] 最大のリスト 'user:1001:feed' が見つかりました。アイテム数 859387

MEMORY USAGEの使用(Redis 4.0以降)

疑わしいキーの正確なサイズをバイト単位で確認するには、MEMORY USAGEコマンドを使用します。これは詳細な診断に不可欠です。

# 特定のキーのメモリ使用量を確認(バイト単位)
redis-cli MEMORY USAGE user:1001:feed

# 出力:(例)84329014

大きなキーを特定した場合は、書き込みパスを確認してください。一般的な修正は、LTRIMを使用したリストのトリミング、一時的な構造の期限切れ、非常に大きなハッシュやソートセットをより小さなキー付きパーティションに分割すること、および「すべてをロードする」読み取りをHSCANSSCAN、またはZSCANなどのページングアクセスに置き換えることです。実際の修正は通常、Redisの設定ではなく、アプリケーションの動作にあります。

戦略4:メモリの断片化とコピーオンライトの管理

高い断片化や突然のRSSスパイクは、しばしばデータリークと誤解されます。これらの問題は、メモリ割り当て、オブジェクトのチャーン、およびフォークベースの永続化に関連しています。

アクティブデフラグメンテーション

アクティブデフラグメンテーションは、サーバーが実行を続けている間に、Redisが無駄なアロケータスペースを再利用するのに役立ちます。これは、さまざまなサイズの値を頻繁に作成および削除するワークロードに役立ちます。また、CPUも使用するため、意図的に有効にし、変更後のレイテンシを監視してください。

redis.confで有効にして設定します。

# アクティブデフラグメンテーションを有効にする
activedefrag yes

# 下限と上限はパーセンテージスタイルの設定値です。
active-defrag-threshold-lower 10
active-defrag-threshold-upper 100

コピーオンライトオーバーヘッドの削減

RedisがRDBスナップショットまたはAOF書き換えのために子プロセスをフォークすると、OSはCoW最適化を使用します。子プロセスがアクティブな間に親プロセスが大量の書き込みを実行すると、書き込まれたすべてのページを複製する必要があり、used_memory_rssが一時的にスパイクします。このスパイクにより、Redisのメモリフットプリントが簡単に2倍になる可能性があります。

軽減策:

  1. トラフィックが少ない時間帯に永続化をスケジュールします。
  2. アロケータのオーバーヘッド、クライアント、レプリケーションバッファ、フォークされた子プロセスのために、maxmemoryの上にメモリの余裕を残します。適切なマージンはデータセットサイズと書き込みレートによって異なります。実際のBGSAVEまたはBGREWRITEAOF中に測定してください。
  3. スナップショット、AOF書き換え、バックアップ、ホストレベルのスキャンなどの重いバックグラウンド作業が重複しないようにします
  4. バッチジョブがコピーオンライトの増加を引き起こしている場合は、永続化中の書き込みチャーンを減らします

最初の対応としてアロケータ環境変数に手を出さないでください。Redisは一般的にjemallocでビルドされており、テストなしでアロケータの動作を変更すると、新しいレイテンシやメモリ動作が発生する可能性があります。アクティブデフラグとワークロードの修正後も断片化が深刻なままの場合は、本番環境に触れる前に、ステージングインスタンスまたはレプリカで変更をテストしてください。

実用的なインシデントフロー

メモリが急増した場合、Redisを再起動する前に事実を収集してください。再起動すると証拠が隠れる可能性があります。

実行:

redis-cli INFO memory
redis-cli INFO persistence
redis-cli DBSIZE
redis-cli --bigkeys

次に、何が変わったのかを尋ねてください。デプロイでTTLが削除されましたか?キューコンシューマーが停止し、リストが増加しましたか?新しいレポートジョブが巨大なハッシュに対してHGETALLを実行しましたか?トラフィックのピーク時にAOF書き換えが開始されましたか?コンテナのメモリ制限が変更されましたか?

最良のRedisメモリ修正は通常、明白です。現実的なmaxmemoryを設定し、ワークロードに一致するエビクションポリシーを選択し、すべてのキャッシュキーにTTLを設定し、無制限の構造を分割し、永続化がメモリの余裕なしで実行されないようにし、インスタンスが限界に達する前にメモリ傾向を警告することです。