慢命令与为什么应该避免 KEYS *:Redis 性能杀手面面观
什么是慢命令
慢命令(Slow Command)是指时间复杂度为 O(N) 或更差、可能阻塞 Redis 主线程并导致服务短暂”卡顿”的操作。由于 Redis 是单线程模型,一个慢命令会阻塞所有后续请求。
最危险的慢命令:KEYS *
KEYS * -- 匹配所有 key
KEYS pattern:* -- 匹配指定模式的 key
KEYS * 的危害
时间复杂度:O(N) —— N 是 key 总数
实际影响:
– 如果 Redis 中有 1000 万个 key,KEYS * 需要遍历所有 key
– 遍历期间 Redis 主线程被阻塞,无法处理其他任何请求
– 可能导致连接超时、服务雪崩
生产事故案例:某公司在线上执行 KEYS user:*,数据库中有 500 万 key,执行耗时 3.2 秒。这 3.2 秒内所有业务请求排队等待,导致接口响应超时,大量连接堆积,最终触发服务雪崩。
其他常见慢命令
1. 集合操作类
| 命令 | 时间复杂度 | 说明 |
|---|---|---|
| SMEMBERS key | O(N) | 获取集合所有成员,N 为集合大小 |
| SINTER key [key…] | O(N*M) | 多个集合交集 |
| SUNION key [key…] | O(N) | 多个集合并集,结果集大 |
| ZRANGE key 0 -1 | O(log(N)+M) | 获取有序集合所有元素 |
| ZREVRANGE key 0 -1 | O(log(N)+M) | 同上,逆序 |
| HGETALL key | O(N) | 获取哈希所有字段,N 为字段数 |
2. 删除操作
DEL key -- O(1) 删除单个 key
DEL key1 key2... -- O(N) 删除大量 key
UNLINK key -- O(1) 异步删除(推荐)
注意:DEL 一个包含大量元素的集合(如 1000 万成员的 Set),也会阻塞 Redis。
3. 排序操作
SORT key [BY pattern] [LIMIT offset count]
时间复杂度通常为 O(N+M*log(M)),N 是集合大小,M 是返回结果数量。
为什么 KEYS * 是”万恶之源”
问题一:复杂度与数据量线性增长
-- 100 万 key: 阻塞约 40ms
-- 500 万 key: 阻塞约 200ms
-- 1000 万 key: 阻塞约 400ms+
问题二:无法预测执行时间
由于 key 数量和遍历时间是线性关系,随着业务增长,执行时间不断膨胀,但代码中很难感知这一点。
问题三:阻塞期间可能引发连锁反应
Redis 阻塞 → 请求排队 → 连接池耗尽 → 客户端超时 → 重试激增 → 雪崩。
SCAN:KEYS * 的安全替代方案
SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
# 安全的遍历方式
def scan_keys(redis, pattern="*", count=100):
cursor = 0
keys = []
while cursor != 0 or not keys:
cursor, batch = redis.scan(cursor, match=pattern, count=count)
keys.extend(batch)
return keys
SCAN 的优点是每次只返回少量数据,不会长时间阻塞主线程。
其他替代方案
| 需要 | 错误做法 | 正确做法 |
|---|---|---|
| 查找匹配的 key | KEYS pattern | SCAN 游标遍历 |
| 获取集合所有元素 | SMEMBERS bigset | SSCAN 游标遍历 |
| 获取哈希所有字段 | HGETALL bighash | HSCAN 游标遍历 |
| 获取有序集合元素 | ZRANGE bigzset 0 -1 | ZSCAN 游标遍历 |
| 删除大量 key | DEL keys* | UNLINK(异步删除) |
| 统计 key 数量 | KEYS * | wc -l | DBSIZE 命令 |
如何发现慢命令
使用 slowlog
SLOWLOG GET 10 -- 获取最近 10 条慢查询
SLOWLOG LEN -- 慢查询日志条数
SLOWLOG RESET -- 清空慢查询日志
配置慢查询阈值(配置文件或命令):
CONFIG SET slowlog-log-slower-than 10000 -- 记录超过 10 毫秒的命令
CONFIG SET slowlog-max-len 1000 -- 保留最后 1000 条
最佳实践清单
- 生产环境严禁在线上使用
KEYS * - 使用
SCAN系列命令进行遍历 - 设置
slowlog监控并定期审查 - 大集合操作考虑拆分为小批次
- 删除大 key 使用
UNLINK而不是DEL - 合理设计 key 命名,避免需要模糊匹配
- 使用
SORT时注意数据量
面试要点
- KEYS * 导致阻塞的核心原因是单线程 + O(N) 复杂度
- 替代方案是 SCAN 系列命令(每次返回有限的元素)
- slowlog 是发现慢命令的重要工具
- UNLINK 是 DEL 的安全替代
- 时间复杂度是 Redis 面试的核心考点
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容