Skip to content

06.3 - 慢查询与性能诊断

定位: Redis 生产环境的性能监控与问题排查方法 面试高频度: ⭐⭐⭐⭐ 考查方式: 延迟排查思路、SLOWLOG 使用、大 key 诊断、热点 key 发现


一、慢查询日志

Redis 自动记录执行时间超过阈值的命令:

配置:
  slowlog-log-slower-than 10000  # 单位微秒,10ms
  slowlog-max-len 128            # 保留最近 128 条

使用:
  SLOWLOG GET 10       # 查看最近 10 条慢查询
  SLOWLOG LEN          # 查看慢查询总数
  SLOWLOG RESET        # 清空慢查询

慢查询输出示例:
  127.0.0.1:6379> SLOWLOG GET 1
  1) 1) (integer) 123          # 唯一 ID
     2) (integer) 1678901234   # Unix 时间戳
     3) (integer) 45678        # 耗时(微秒)= 45.678ms
     4) 1) "KEYS"              # 命令
        2) "user:*"            # 参数
     5) "127.0.0.1:12345"     # 客户端
     6) "my-application"      # 客户端名称

二、延迟排查

2.1 redis-cli 自带延迟工具

bash
# 延迟监控
redis-cli --latency          # 持续显示延迟
# min: 0, max: 1, avg: 0.12 (1079 samples)

redis-cli --latency-history  # 每 15 秒报告一次
# min: 0, max: 3, avg: 0.15 (14372 samples) -- 15.01 seconds

redis-cli --latency-dist     # 延迟分布柱状图(可视化)

# 内置延迟测试(服务端记录)
redis-cli DEBUG SLEEP 0.5   # 模拟 500ms 延迟(会阻塞!)
redis-cli --latency
# 你会看到 max 跳到 500ms 以上

2.2 延迟来源

延迟来源排查清单

  1. 网络延迟redis-cli --latency -h <remote_ip>,如果 avg > 1ms,可能是网络问题

  2. 慢命令(阻塞事件循环):KEYS *、SMEMBERS、HGETALL、ZRANGE、LRANGE 都是 O(N) 操作!替代:SCAN/SSCAN/HSCAN/ZSCAN 分批

  3. Fork 阻塞:BGSAVE / BGREWRITEAOF → fork(),大内存实例 fork 可能阻塞 100-500ms,所有请求在这段时间等待。缓解:只在从节点做持久化

  4. 写时复制(COW)内存翻倍:bgsave 期间大量写入 → COW 复制 → 内存翻倍 → swap → 延迟暴增。监控:rdb_last_cow_size


三、热点 key 发现

热点 key = 被大量请求集中访问的 key

问题:
  一个 key 每秒被访问 10 万次
  → 该命令排队执行
  → 虽然 Redis 单机 10 万 QPS 没问题
  → 但这个 key 的访问占据了大部分 CPU

发现方法:

方法 1:redis-cli --hotkeys(Redis 4.0+)
  redis-cli --hotkeys
  # 扫描并统计访问频率最高的 key
  # 需要启用 LFU 策略

方法 2:MONITOR 抽样
  redis-cli MONITOR | head -10000 | awk '{print $4}' | sort | uniq -c | sort -nr | head -10
  # 统计 TOP 10 访问的 key

方法 3:客户端自定义
  在 Redis 客户端统计每个 key 的访问次数
  (最好在客户端做,不增加 Redis 负担)

解决热点 key:
  ✓ 本地缓存(Caffeine/Guava Cache)——热点 key 在应用内存缓存
  ✓ 读写分离(从节点分担读请求)
  ✓ 多个副本(不同 key 名,random 路由)
  ✓ Hash Tag 拆分(一个大 key 拆成多个 key)

四、实战验证

4.1 慢查询操作

bash
# 1. 配置慢查询阈值(100ms)
redis-cli CONFIG SET slowlog-log-slower-than 100000

# 2. 执行一个慢命令
redis-cli KEYS "*"  # 全量扫描(在大量 key 时很慢)

# 3. 查看慢查询
redis-cli SLOWLOG GET 5
# 1) 1) (integer) 1
#    2) (integer) 1678901234
#    3) (integer) 152345   # 152ms!
#    4) 1) "KEYS"
#       2) "*"

# 4. 查看慢查询统计
redis-cli SLOWLOG LEN
# (integer) 1

4.2 延迟诊断

bash
# 1. 基准延迟测试
redis-cli --latency -h 127.0.0.1 -p 6379
# min: 0, max: 2, avg: 0.11

# 2. 模拟大 key 对延迟的影响
redis-cli SET bigkey "$(dd if=/dev/zero bs=1M count=10 2>/dev/null | base64)"
redis-cli --latency &
redis-cli GET bigkey > /dev/null  # 在另一个窗口执行
# ← 延迟从 avg 0.11ms 跳到 max 85ms

# 3. 模拟慢命令
redis-cli --latency &
redis-cli DEBUG SLEEP 2  # 另一个窗口:模拟 2 秒阻塞
# ← 延迟跳到 2000ms(所有请求被阻塞 2 秒)

# 4. 查看服务器内部延迟统计
redis-cli INFO commandstats
# cmdstat_get:calls=100,usec=500,usec_per_call=5.00
# cmdstat_set:calls=200,usec=800,usec_per_call=4.00
# cmdstat_keys:calls=1,usec=152345,usec_per_call=152345.00  ← 这个太慢了!

4.3 连接和内存监控

bash
# 当前连接数
redis-cli CLIENT LIST | wc -l
redis-cli INFO clients
# connected_clients:50
# client_longest_output_list:0

# 观察阻塞的客户端
redis-cli CLIENT LIST | grep -E "obl|oll"
# obl: 输出缓冲区长度
# oll: 输出链表长度

# 查看内存状态
redis-cli INFO memory
# evicted_keys: 1000  ← 被淘汰的 key 数量(如果 >0 说明内存不够)
# keyspace_hits: 100000
# keyspace_misses: 500
# 命中率 ≈ 99.5%

4.4 热 key 排查

bash
# MONITOR 方法(生产谨慎使用,会降低 50% 性能!)
redis-cli MONITOR | head -1000 | grep -v "PING" | awk '{print $4}' | sort | uniq -c | sort -nr | head -10

# --hotkeys 方法(安全,需要 LFU 策略)
redis-cli --hotkeys

# 观察 key 的过期频率
redis-cli INFO stats | grep expired_keys
# expired_keys: 5000  ← 如果很高,检查过期时间配置

五、面试视角

追问答案要点
怎么排查 Redis 延迟突增?① redis-cli --latency 看基准 → ② SLOWLOG 看慢命令 → ③ 网络 ping → ④ 检查 fork/fragmentation
KEYS * 为什么不建议用?O(N) 阻塞单线程,1000 万 key → 阻塞几十秒。用 SCAN 代替
什么是慢查询阈值?slowlog-log-slower-than 微秒,超过的记录到 slowlog;不限制执行,只记录日志
MONITOR 命令的代价?会降低 Redis 50%+ 的性能,仅调试用,生产慎用
热点 key 怎么解决?本地缓存 + 副本 key + 读写分离 + 拆分
如何监控内存不足?evicted_keys > 0 表示开始淘汰,used_memory 接近 maxmemory 时预警
INFO commandstats 的作用?查看每个命令的调用次数、总耗时和平均耗时,发现耗时高的命令

📚 相关链接

  • **内存优化** — 内存问题的诊断与解决
  • **Pipeline** — 性能优化的重要手段
  • **AOF** — AOF 阻塞的诊断
  • ← 返回 **性能优化与运维索引**

Knowledge4J — Java 知识库