Prevent common Redis performance and stability issues, applicable to all languages.
Prohibited Operations
| Prohibited | Alternative | Reason |
|---|---|---|
KEYS * / KEYS pattern |
SCAN Cursor iteration |
KEYS is an O(N) blocking operation and will cause Redis to freeze in production environments |
FLUSHDB / FLUSHALL |
SCAN + DEL by key prefix | The risk of full deletion is extremely high |
| SET without TTL | All keys must have a TTL set | Avoid memory leaks |
Must Comply
1. Use SCAN instead of KEYS
// Go (go-redis) ❌
keys, _ := rdb.Keys(ctx, "user:*").Result()
// Go (go-redis) ✅
var cursor uint64
for {
keys, cursor, _ = rdb.Scan(ctx, cursor, "user:*", 100).Result()
// 处理 keys
if cursor == 0 { break }
}
// Java (Jedis) ❌
Set<String> keys = jedis.keys("user:*");
// Java (Jedis) ✅
ScanParams params = new ScanParams().match("user:*").count(100);
String cursor = "0";
do {
ScanResult<String> result = jedis.scan(cursor, params);
// 处理 result.getResult()
cursor = result.getCursor();
} while (!cursor.equals("0"));
# Python (redis-py) ❌
keys = r.keys("user:*")
# Python (redis-py) ✅
for key in r.scan_iter(match="user:*", count=100):
# 处理 key
2. Large key control
- The value of a single key must not exceed 10KB
- Elements in collection types (List/Set/Hash/ZSet) must not exceed 5000 items
- Split into multiple keys when exceeded
3. Pipeline batch operations
Multiple Redis calls should use Pipeline to reduce network round trips:
// ❌ 循环单次调用
for _, id := range ids {
rdb.Get(ctx, "user:"+id)
}
// ✅ Pipeline 批量
pipe := rdb.Pipeline()
for _, id := range ids {
pipe.Get(ctx, "user:"+id)
}
pipe.Exec(ctx)
4. Set TTL for all keys
// ❌
rdb.Set(ctx, "token:123", value, 0)
// ✅
rdb.Set(ctx, "token:123", value, 24*time.Hour)