1. 慢查询概念入门

1.1 什么是 Redis 慢查询

Redis 慢查询并非指 SQL 意义上的慢查询,而是指 命令执行耗时超过预设阈值 的操作。Redis 是单线程模型,所有命令按顺序排队执行;当某个命令处理时间过长,就会阻塞后续命令,导致整体吞吐量下降。

Redis 内部通过 slowlog-log-slower-than 和 slowlog-max-len 两个配置项来定义和记录慢查询:

配置项 默认值 说明
slowlog-log-slower-than 10000(微秒,即 10ms) 命令执行时间超过此值即被记录为慢查询
slowlog-max-len 128 慢查询日志队列最大长度,超出后淘汰最旧记录
关键理解: 慢查询的判定单位是微秒(μs),1ms = 1000μs。默认 10ms 的阈值对于高并发场景已经偏大,生产环境通常建议调低至 1ms~5ms。

查看当前慢查询配置:

127.0.0.1:6379> CONFIG GET slowlog-log-slower-than
1) "slowlog-log-slower-than"
2) "10000"

127.0.0.1:6379> CONFIG GET slowlog-max-len
1) "slowlog-max-len"
2) "128"

查看慢查询日志:

127.0.0.1:6379> SLOWLOG GET 5
1) 1) (integer) 14        # 日志唯一ID
   2) (integer) 1712345678 # Unix时间戳
   3) (integer) 45678      # 执行耗时(微秒)
   4) 1) "KEYS"            # 命令及参数
      2) "user:*"
   5) "127.0.0.1:6379"     # 客户端地址
   6) "user-agent=redis-cli"

1.2 慢查询的危害

Redis 单线程模型决定了一个慢查询阻塞所有后续命令。其危害呈链式放大:

  • 请求排队延迟: 慢查询执行期间,后续所有命令都在队列中等待,造成整体响应时间飙升。
  • 连接堆积: 客户端等待超时后重试,导致 Redis 连接数暴涨,甚至触发 maxclients 限制。
  • 缓存雪崩风险: 慢查询集中在热点 Key 时,可能导致缓存大面积失效,请求穿透至数据库。
  • 主从复制延迟: 主节点慢查询会延迟生成 RDB/AOF 或增量同步,从节点数据滞后加剧。
  • 运维盲区: 未记录的慢查询会反复出现,成为性能隐患的“定时炸弹”。
真实案例: 某电商平台大促期间,一个 KEYS * 命令执行耗时 12 秒,导致 Redis 线程阻塞,上游服务超时雪崩,最终核心交易接口 502 持续 3 分钟。事后复盘发现该命令来自一个未上线的调试脚本。

1.3 为什么需要复盘慢查询

复盘慢查询不是简单的“查日志、改配置”,而是建立持续性能治理的起点:

  1. 定位根因: 区分是命令本身低效(如 KEYS、HGETALL 大 Key)、数据量膨胀、还是网络/CPU 资源竞争。
  2. 量化影响: 通过慢查询频率、耗时分布、关联业务接口,评估对 SLA 的实际冲击。
  3. 制定优化策略: 针对不同根因采取不同手段——拆分大 Key、改用 SCAN、升级数据结构、调整阈值等。
  4. 建立预防机制: 将慢查询监控纳入告警体系,设置分级阈值(警告/严重),避免问题反复发生。
  5. 沉淀知识库: 每次复盘形成可复用的排查清单和优化模板,提升团队整体运维效率。
复盘核心公式: 慢查询复盘 = 发现(监控)→ 定位(日志+上下文)→ 分析(根因+影响)→ 优化(代码/配置/架构)→ 验证(压测+灰度)→ 沉淀(文档+告警规则)。
Redis 慢查询影响链路 慢查询命令 Redis 线程阻塞 后续命令排队 客户端连接堆积 主从复制延迟 缓存雪崩风险 上游服务雪崩 单线程模型下 一个慢查询引发连锁反应

1.4 慢查询的判定与记录机制

Redis 慢查询日志采用固定长度环形队列存储,不会写入磁盘,重启后丢失。其工作流程如下:

  • 计时起点: 命令从 socket 读取完成后开始计时,不包括排队等待时间。
  • 计时终点: 命令执行完成(结果返回给客户端前)停止计时。
  • 阈值比较: 执行耗时 > slowlog-log-slower-than 则入队。
  • 队列淘汰: 队列满时,最旧的慢查询记录被移除。
注意: 慢查询日志只记录命令执行耗时,不包含网络传输、排队等待时间。因此实际业务感知的延迟往往比慢查询日志显示的更大。

1.5 常见慢查询命令速查

命令 时间复杂度 慢查询风险 优化建议
KEYS * O(N) 极高 使用 SCAN 替代
SMEMBERS O(N) 高(大 Set) 使用 SSCAN 或拆分 Set
HGETALL O(N) 高(大 Hash) 使用 HSCAN 或字段拆分
LRANGE O(N) 中(大 List) 限制返回范围,拆分 List
ZRANGE O(log(N)+M) 中(大 Zset) 限制返回数量,使用索引
SORT O(N+M*log(M)) 高 避免在大量数据上排序
最佳实践: 生产环境建议将 slowlog-log-slower-than 设置为 1000~3000 微秒(1~3ms),slowlog-max-len 设置为 1024 以上,确保慢查询日志能覆盖足够长的排查窗口。