RedisがCPUを高使用する理由:デバッグと最適化テクニック

重要なインメモリデータストアであるRedisにおける突然のCPU高使用率を調査します。このガイドでは、`SLOWLOG`や`INFO`コマンドを使用して負荷をデバッグし、`KEYS *`や大規模なキー削除などの非効率な操作を特定する方法を詳しく説明します。非同期の`UNLINK`への切り替え、パイプラインの活用、永続性設定のチューニングなど、実践的な最適化テクニックを学び、サーバー負荷を即座に軽減し、最適なRedisパフォーマンスを回復します。

RedisがCPUを高使用する理由:デバッグと最適化テクニック

RedisのCPU使用率が高い場合、通常は次の3つのいずれかを意味します:Redisがメイン実行パスで過剰なコマンド処理を行っている、永続性などのバックグラウンド作業が負荷をかけている、またはクライアントがRedisが効率的に処理できない形でトラフィックを送信している。修正方法は、どれが原因かによって異なります。

サービスがすでにダウンしている場合を除き、Redisを再起動してはいけません。再起動は症状を一時的に取り除くかもしれませんが、証拠を消してしまいます。まず、コマンドレイテンシ、コマンドの種類、クライアント数、永続性の状態、ホストCPUを取得しましょう。これらの情報から、悪いコマンド、悪いトラフィックパターン、過負荷のシングルコア、またはノイズの多いホストのいずれが原因かがわかります。

RedisのアーキテクチャとCPU負荷の理解

Redisはしばしばシングルスレッドと説明されますが、これはコマンド実行に関してはほぼ正しいですが、現代のRedisはバックグラウンドスレッドやオプションのI/Oスレッドも使用できます。実用的なポイントは同じです:時間がかかりすぎるコマンドは他のクライアントを遅延させ、1つのコアが飽和すると、マシンに他のアイドルCPUがあっても、目に見えるレイテンシを引き起こす可能性があります。

RedisのCPU負荷に影響を与える主な要因

一般的な原因は、高コストなコマンド、大きな値、Luaスクリプト、1ラウンドトリップあたりに送信される小さなコマンドが多すぎる、大量の接続の変動、永続性アクティビティ、およびRedisが予想するよりもカーネルがハードに動作する原因となるメモリプレッシャーです。

高いCPU使用率のデバッグ

最適化する前に、負荷の原因を正確に特定する必要があります。監視ツールと組み込みのRedisコマンドが診断に不可欠です。

1. INFOおよびLATENCYコマンドの使用

INFOコマンドはサーバーステータスのスナップショットを提供します。CPUセクションとコマンド統計に注目してください。

redis-cli INFO cpu

絶対値だけでなく、変化率にも注目してください。used_cpu_userが急速に増加している場合、多くの場合コマンド処理を示しています。used_cpu_sysが急速に増加している場合、ネットワーキング、メモリ管理、ディスク関連アクティビティなどのカーネル作業を示している可能性があります。

レイテンシツールは、Redisが観測したイベントクラスを示します:

redis-cli LATENCY LATEST
redis-cli LATENCY DOCTOR

2. SLOWLOGを使用した低速コマンドの特定

Redis Slow Logは、指定された実行時間を超えるコマンドを記録します。これは、パフォーマンスの低い操作を見つけるための最も直接的なツールです。

Redisスローログは、実行時間がしきい値を超えるコマンドを記録します。ネットワーク時間やクライアントプールでの待機時間は含まれないため、アプリケーションレイテンシメトリクスと併用するのが最適です。

設定例:

slowlog-log-slower-than 1000
slowlog-max-len 1024

ログの取得:

redis-cli SLOWLOG GET 10

コマンド名、キー名、および期間を確認します。KEYS、大規模なHGETALL、巨大なSMEMBERS、広範囲のソート済みセット範囲、またはLuaスクリプトがログを支配している場合、CPUの問題はおそらくアプリケーション主導です。

3. ネットワークとクライアントアクティビティの監視

インシデント中はMONITORが魅力的ですが、ビジーなサーバーではコストがかかります。INFO commandstatsINFO clients、スローログ、クライアントライブラリメトリクス、およびレプリカがある場合はそこからのサンプリングを優先してください。

便利なコマンド:

redis-cli INFO commandstats
redis-cli INFO clients
redis-cli CLIENT LIST

デプロイ後にコマンドボリュームが倍増した場合、cmdstat_getcmdstat_hgetall、または同様のカウンターで確認できるかもしれません。クライアントが常に接続と切断を繰り返している場合は、Redisをチューニングする前にプーリングを修正してください。

一般的な原因と最適化戦略

問題のあるコマンドやプロセスを特定したら、対象を絞った最適化テクニックを適用します。

1. ブロッキングコマンドの排除

最も迅速な改善は、Redisに巨大なキースペースをスキャンさせたり、巨大な値をシリアライズさせたりするコマンドを削除することから得られることがよくあります。

非効率なコマンド CPU高使用の原因 最適化 / 代替案
KEYS * キースペース全体をスキャン。O(N)。 SCANを反復的に使用するか、データアクセスを再構築する。
FLUSHALL / FLUSHDB 非同期モードを使用しない限り、すべてのキーを削除。 注意深くスコープされた削除、UNLINK、または適切な場合のみ非同期フラッシュを使用。
HGETALLSMEMBERS(非常に大きなセットの場合) 構造全体をメモリに取得し、シリアライズ。 HSCANSSCANを使用するか、大きな構造をより小さなキーに分割。

非常に大きなキーにはDELの代わりにUNLINKを使用してください。DELは同期的にメモリを解放します。UNLINKはキースペースからキーを削除し、非同期的にメモリを解放するため、大規模な削除中の可視レイテンシが通常減少します。

# DEL large_key の代わりに
UNLINK large_key

2. 永続性の最適化(RDBとAOF)

RDBスナップショットとAOF書き換えはバックグラウンド子プロセスを使用し、フォークコスト、コピーオンライトメモリ、ディスク帯域幅、CPU競合を通じて親プロセスに影響を与える可能性があります。

  • RDBスナップショット: 頻繁に保存している場合(例:毎分)、繰り返されるfork()呼び出しは再発するCPUスパイクを引き起こします。自動保存の頻度を減らしてください。
  • AOF書き換え: AOF書き換え(BGREWRITEAOF)もリソースを大量に消費します。Redisは最小限のI/Oでこれを最適化しようとしますが、プロセス中にCPU使用率が上昇します。

永続性がCPUスパイクと一致する場合は、INFO persistenceとホストディスクメトリクスを確認してください。RDB頻度を減らし、重いバックアップをトラフィックピークから遠ざけ、メモリヘッドルームを多く残すか、ストレージを改善できます。永続性を一時停止すると負荷は軽減されますが、データ損失のリスクも高まるため、意図的な運用上の決定であるべきです。

3. メモリ断片化とスワッピングの処理

メモリの問題はしばしば高いメモリ使用率に関連付けられますが、深刻なメモリ断片化、またはさらに悪いことに、オペレーティングシステムがRedisデータをディスクにスワップし始める(スラッシング)と、カーネルがメモリを管理しようと奮闘するため、CPU使用率が劇的に増加します。

  • スワッピングの確認: OSツール(vmstattop)を使用して、システムがRedisプロセスに属するメモリページをアクティブにスワップしているかどうかを確認します。
  • メモリ断片化率: INFO memorymem_fragmentation_ratioを確認します。高い比率はアロケータの動作がメモリを浪費している可能性を示唆しますが、RSS、データセットサイズ、ホストメモリメトリクスで確認してください。

スワッピングが発生している場合は、データセットを減らし、maxmemoryを下げ、ホストから作業を移動するか、メモリを追加してください。Redisは、ホットデータセットがディスクにページングされている場合、良好に動作するようには設計されていません。

4. ネットワーク最適化とパイプライン

CPU負荷が多数の小さなコマンドに追従している場合、問題は明らかに遅いコマンドではなく、コマンドオーバーヘッドとネットワークの変動である可能性があります。

パイプラインを使用すると、クライアントは各コマンドの応答を待たずに複数のコマンドを送信できます。これによりラウンドトリップが削減され、バルク書き込みや読み取りのスループットが向上します。パイプラインバッチは制限されたサイズに保ってください。数千の重いコマンドを含むパイプラインは、独自のレイテンシスパイクを引き起こす可能性があります。

持続的なパフォーマンスのためのベストプラクティス

将来のCPUスパイクを防ぐために、以下のアーキテクチャおよび設定のベストプラクティスを採用してください:

  1. 大きな可能性のあるキーにはUNLINKを使用する。
  2. KEYSSCANに置き換え、完全なコレクション読み取りをカーソルベースの読み取りに置き換える。
  3. デプロイ後にINFO commandstatsを追跡し、新しいコマンドパターンに驚かないようにする。
  4. 実際のディスクとメモリのヘッドルームを考慮して永続性をチューニングする。
  5. コマンド修正後も1つのRedisインスタンスが正当に飽和している場合は、Redis Cluster、クライアントサイドシャーディング、別のキャッシュ/セッションインスタンス、またはより良いシングルコアパフォーマンスを持つ大きなインスタンスでワークロードを分割する。

クイックインシデントチェックリスト

スパイク中に、以下を実行してください:

redis-cli INFO cpu
redis-cli INFO commandstats
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli SLOWLOG GET 20
redis-cli LATENCY LATEST

次に、これらの結果をアプリケーションデプロイ、cronジョブ、トラフィック変更、永続性イベント、およびホストメトリクスと照合します。高いRedis CPUは通常修正可能ですが、修正は具体的です:高コストなコマンドを削除する、おしゃべりなクライアントをバッチ処理する、接続の変動を止める、永続性に作業スペースを与える、または単一インスタンスが本当に限界に達した場合にワークロードを分割する。