Redisクライアントと接続設定に関するガイダンスです。接続プーリング(複数の接続を効率的に再利用する仕組み)、マルチプレキシング(複数のタスクを一つの接続で処理)、パイプライニング(複数のコマンドを一括送信)、RESP3を使ったクライアント側のキャッシング、遅い処理(KEYS、SMEMBERS、HGETALL)の回避、ソケットタイムアウトの調整などを扱います。 次のような場合に使用: Redisクライアント(redis-py、Jedis、Lettuce、NRedisStackなど)を設定する、複数のコマンドをまとめて実行してスループット(単位時間当たりの処理量)を高める、リクエストごとの接続作成を減らす、SCENコマンドで大量のキーを安全に検索する、読み取りが多い用途でクライアント側キャッシングを有効にする、接続確立とデータ読み込みのタイムアウト時間を設定する場合。
Redis client and connection guidance covering connection pooling, multiplexing, pipelining, client-side caching with RESP3, avoiding slow commands (KEYS, SMEMBERS, HGETALL), and tuning socket timeouts. Use when configuring a Redis client (redis-py, Jedis, Lettuce, NRedisStack), batching commands for throughput, eliminating per-request connection creation, iterating large keyspaces with SCAN, enabling client-side caching for read-heavy workloads, or setting connect and read timeouts.
Redisと効率的に通信するためのクライアント側の指針:接続の共有方法、コマンドのまとめ方、本番環境で呼び出してはいけないコマンド、クライアント側キャッシング(クライアントが保持するデータの一時保存機能)をいつ有効にするか、そして高速な失敗を実現しながら正常なトラフィックを損なわないタイムアウトの設定方法について説明します。
Redisクライアントコードにおける最大の落とし穴は、操作のたびに新しいTCP接続を開くことです。必ず以下のいずれかを採用してください:
ConnectionPool、Jedis の JedisPooled、go-redis クライアント)| 方式 | 使用ライブラリ | 説明 |
|---|---|---|
| プール | redis-py、Jedis、go-redis | プールが枯渇した場合、リクエストはブロックされます。同時実行数に合わせてプールサイズを設定してください |
| 多重化 | Lettuce、NRedisStack | 単一接続を使用。BLPOPなどのブロッキングコマンドは実行できません |
# redis-py — 接続プール
pool = redis.ConnectionPool(host="localhost", port=6379, max_connections=50)
r = redis.Redis(connection_pool=pool)
詳細はPython・Java・Lettuceの例を含む「参考資料/pooling.md」をご覧ください。
互いに結果に依存しないN個のコマンドについては、パイプライニング(複数コマンドをまとめて送信)で単一バッチとして送信してください。N回のやり取りではなく、1回で済みます。
pipe = redis.pipeline()
for user_id in user_ids:
pipe.get(f"user:{user_id}")
results = pipe.execute()
パフォーマンスを優先してトランザクション非対応のパイプライニングを使用し、実際に一貫性が必要な場合のみ pipeline(transaction=True) を使ってください(redis-coreのトランザクション指針を参照)。
詳細は「参考資料/pipelining.md」をご覧ください。
キースペース全体(または大規模なコンテナ全体)を走査するコマンドはサーバーをブロックします。代わりに段階的な代替手段を使ってください。
| 避けるべき | 代わりに使用 |
|---|---|
KEYS pattern |
SCAN カーソルループ |
SMEMBERS large_set |
SSCAN |
HGETALL large_hash |
HSCAN |
巨大なリストに対する LRANGE 0 -1 |
ページネーション(LRANGE 0 100など) |
cursor = 0
while True:
cursor, keys = redis.scan(cursor, match="user:*", count=100)
for key in keys:
process(key)
if cursor == 0:
break
ブロッキングコマンド(BLPOP、BRPOP、BLMOVE)は別物です ——データを待機することが本来の目的であり、キュー消費者には適しています。ただし、必ずタイムアウトを指定し、多重化接続(Lettuce、NRedisStack)では発行しないようにしてください。
詳細は「参考資料/blocking.md」をご覧ください。
設定やフィーチャーフラグ、リクエストごとのセッション情報など、読み取りが頻繁で書き込みが稀なデータについては、RESP3プロトコル対応のクライアント側キャッシングを有効にしてください。クライアントがローカルコピーを保持し、サーバーが書き込み時に無効化することで、アクセス頻度の高い読み取りでのやり取りが削減されます。
client = redis.Redis(
host="localhost",
port=6379,
protocol=3, # RESP3が必須
cache_config=redis.CacheConfig(max_size=1000),
)
書き込みが多い場合や常に変わり続けるデータに対しては、無効化トラフィックが節約効果を上回るため、スキップしてください。
詳細は「参考資料/client-cache.md」をご覧ください。
デフォルト値はクライアントごとに異なり、過度に大きい可能性があります。アプリケーションの障害モデルに合わせて値を選択してください:
r = redis.Redis(
host="localhost",
socket_connect_timeout=2.0, # ダウンしたノードで高速に失敗
socket_timeout=5.0, # 予想される操作時間に合わせて調整
retry_on_timeout=True,
)
経験則:接続タイムアウトは読み書きタイムアウトより短くしてください。遅延に敏感なパスでは短いタイムアウト+再試行、バッチジョブではより長いタイムアウトを採用します。
詳細は「参考資料/timeouts.md」をご覧ください。
Client-side guidance for talking to Redis efficiently: how to share connections, how to batch commands, which commands not to call in production, when to turn on client-side caching, and how to set timeouts that fail fast without breaking healthy traffic.
The single biggest mistake in Redis client code is opening a new TCP connection for every operation. Always either:
ConnectionPool, Jedis JedisPooled, go-redis client).| Style | Used by | Note |
|---|---|---|
| Pool | redis-py, Jedis, go-redis | Each lease blocks if pool exhausted; size the pool to your concurrency |
| Multiplex | Lettuce, NRedisStack | Single connection; cannot carry blocking commands like BLPOP |
# redis-py — connection pool
pool = redis.ConnectionPool(host="localhost", port=6379, max_connections=50)
r = redis.Redis(connection_pool=pool)
See references/pooling.md for Python + Java + Lettuce examples.
For N commands that don't depend on each other's results, send them as a single batch with pipelining. One round-trip instead of N.
pipe = redis.pipeline()
for user_id in user_ids:
pipe.get(f"user:{user_id}")
results = pipe.execute()
Use non-transactional pipelining for performance, and pipeline(transaction=True) only when you actually need atomicity (see redis-core's transactions guidance).
Anything that walks the whole keyspace (or a whole large container) blocks the server. Use incremental variants instead.
| Don't | Use |
|---|---|
KEYS pattern |
SCAN cursor loop |
SMEMBERS large_set |
SSCAN |
HGETALL large_hash |
HSCAN |
LRANGE 0 -1 on a huge list |
Paginate (LRANGE 0 100) |
cursor = 0
while True:
cursor, keys = redis.scan(cursor, match="user:*", count=100)
for key in keys:
process(key)
if cursor == 0:
break
Blocking commands (BLPOP, BRPOP, BLMOVE) are different — they intentionally wait for data and are fine for queue consumers, but always pass a timeout, and don't issue them on a multiplexed connection (Lettuce, NRedisStack).
For data that's read often and written rarely (config, feature flags, sessions on every request), enable RESP3 client-side caching. The client keeps a local copy and the server invalidates it on writes — saving the round trip for hot reads.
client = redis.Redis(
host="localhost",
port=6379,
protocol=3, # RESP3 is required
cache_config=redis.CacheConfig(max_size=1000),
)
Skip it for write-heavy workloads or data that changes constantly — the invalidation traffic overruns the savings.
See references/client-cache.md.
Defaults vary by client and may be too generous. Pick values that match the application's failure model:
r = redis.Redis(
host="localhost",
socket_connect_timeout=2.0, # fail fast on dead nodes
socket_timeout=5.0, # tune to expected operation time
retry_on_timeout=True,
)
Rule of thumb: connect timeout shorter than read/write timeout. Tight timeouts + retry-on-timeout for latency-sensitive paths; longer timeouts for batch jobs.
原文・著作権は Anthropic および各プラグイン作者に帰属します。日本語訳は Claude API による自動翻訳です。