画像データ保存におけるデータ型の選択
画像データのメタデータを保存する際、StringやHash以外にSorted Setを利用する手法があります。具体的には、画像IDの前半部分をキーとし、後半部分をメンバ(member)、画像オブジェクトの内部IDをスコア(score)として保存します。この手法でも、要素数が少ないうちは内部的に「ziplist(圧縮リスト)」が使用されるため、メモリ消費を抑えることが可能です。
しかし、Sorted Setは挿入時にスコアに基づいたソート処理が発生します。ziplist構造の場合、このソート負荷により挿入パフォーマンスがHashに劣るため、画像保存のような書き込み頻度の高いケースではHashの方が一般的に有利です。
多様な統計処理とリストの活用
単純な集計以外に、直近のイベント到達率を算出するようなケースでは、List型とLuaスクリプトを組み合わせる手法が有効です。例えば、直近200件のユーザーアクションを0(失敗)と1(成功)でListにプッシュし、統計が必要な際に全件取得して計算します。データ量が数百件程度であれば実用的ですが、数万件を超える場合や特定の要素へのランダムアクセスが必要な場合は、計算量の観点からHash型やBitmap型への移行を検討すべきです。
時系列データにおけるSorted Setの副作用
Sorted Setを時系列データの保存に使用する場合、タイムスタンプをスコアに、値をメンバに設定すると、同一の値が重複した際に古いデータが最新のタイムスタンプで上書きされるリスクがあります。これはSetの「メンバのユニーク性」に起因します。センサーデータのように同じ値が連続して発生する環境では、メンバ側にタイムスタンプを混ぜるなどの工夫が必要です。
また、Redis内での集計処理(Aggregation)の実装については、Redisがシングルスレッドモデルであることを考慮する必要があります。複雑な集計を組み込み関数として持たせるとCPUリソースを過剰に消費し、本来の高速な読み書きを阻害するため、集計処理はクライアント側や専用の計算レイヤーで行うのが定石です。
メッセージング:複数消費者への配信
一つのメッセージを複数の異なるシステム(例:リアルタイム解析エンジンとHDFS蓄積用ワーカー)で処理したい場合、Redis Streamsの「コンシューマグループ」機能を活用します。ただし、同一グループ内の消費者はメッセージを奪い合うため、システムごとに独立したグループを作成する必要があります。あるいは、古くからあるPub/Sub機能を利用することで、ブロードキャスト型の配信も可能です。
マルチコア環境におけるデプロイ戦略
2つのCPUソケットを持つサーバーで複数のRedisインスタンスを運用する場合、単一のソケットに全インスタンスを詰め込むのではなく、ソケットを分散させて配置することを推奨します。これは、L3キャッシュの競合回避と、NUMA(Non-Uniform Memory Access)によるメモリアクセスの遅延を防止するためです。ソケットを跨いだメモリ参照が発生すると、パフォーマンスが顕著に低下します。
スロークエリの特定とモニタリング
Redisの応答が遅延している場合、まずはスローログを確認します。以下の設定により、指定した実行時間を超えるコマンドを記録できます。
# 10ミリ秒(10000マイクロ秒)を超えるコマンドを記録
CONFIG SET slowlog-log-slower-than 10000
# ログの保持件数を1000件に設定
CONFIG SET slowlog-max-len 1000
記録されたログは SLOWLOG GET [件数] で取得できます。また、バージョン2.8.13以降では latency monitor を使用して、スパイク的な遅延を可視化することも可能です。
# 閾値を1ミリ秒に設定
CONFIG SET latency-monitor-threshold 1
# 最新の遅延状況を確認
LATENCY LATEST
Bigkey(巨大なキー)の検出と対処
単一のキーに膨大なデータが含まれる「Bigkey」は、主スレッドをブロックする大きな要因となります。以下のコマンドで、各データ型における最大サイズのキーをスキャンできます。
./redis-cli --bigkeys -i 0.05
-i オプションはスキャンの合間にスリープを挟むためのもので、本番環境への負荷を軽減します。さらに詳細なメモリ使用量を知りたい場合は、MEMORY USAGE コマンドを個別のキーに対して実行します。
# 指定したキーのメモリ占有量をバイト単位で取得
MEMORY USAGE user_session:9901
メモリ断片化率(mem_fragmentation_ratio)の解釈
断片化率が1を下回る場合、Redisが要求しているメモリ量に対して、OSが割り当てた物理メモリが不足していることを意味します。この状態ではスワップが発生しており、ディスクI/O待ちによってRedisのパフォーマンスは壊滅的に低下します。即座にメモリ増設か、データの削減が必要です。