3. 热点Key识别与监控
热点Key(Hot Key)是指在一段时间内被大量并发访问的Redis Key。当热点Key的QPS超过单节点处理能力时,会导致Redis实例CPU飙升、请求超时甚至雪崩。本章聚焦于四种主流识别手段:Monitor命令、Slow Log、Big Keys扫描以及客户端统计,并给出生产环境下的组合策略。
核心原则:热点识别应作为常态化监控任务,而非事后救火手段。建议将识别周期控制在分钟级,并联动告警系统自动触发削峰策略。
3.1 四种识别手段对比
| 手段 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| MONITOR | 实时打印所有命令 | 全量可见,精准定位Key | 高并发下性能损耗大,可能撑爆输出缓冲区 | 临时排查、低流量环境 |
| SLOWLOG | 记录执行时间超阈值的命令 | 低开销,自动记录 | 仅反映慢查询,不直接反映高频访问 | 识别大Key或复杂命令导致的延迟 |
| BIGKEYS | 扫描并统计大Key分布 | 直接定位大Key,辅助分析热点成因 | 扫描期间可能阻塞,需避开高峰期 | 大Key导致的热点问题 |
| 客户端统计 | 在SDK侧统计Key访问频次 | 零侵入,无性能损耗,可定制化 | 需改造客户端代码,多语言维护成本 | 生产环境长期监控 |
3.2 MONITOR 命令实战
MONITOR 会实时输出Redis处理的所有命令,适合临时抓取热点Key。但务必注意:生产环境开启MONITOR会使Redis吞吐量下降50%以上,建议仅在低峰期或从节点执行。
# 在redis-cli中开启MONITOR
redis 127.0.0.1:6379> MONITOR
OK
# 输出示例(实时流)
1627989123.456789 [0 10.0.0.1:54321] "GET" "product:1001"
1627989123.456890 [0 10.0.0.2:54322] "GET" "product:1001"
1627989123.456912 [0 10.0.0.3:54323] "GET" "product:1002"
...
通过管道将输出重定向到文件,再用脚本统计Key出现频率:
# 采集30秒后统计Top 10热点Key
timeout 30 redis-cli MONITOR > monitor.log
awk '{for(i=5;i<=NF;i++) if($i ~ /^"[A-Z]+"/) print $i}' monitor.log \
| sort | uniq -c | sort -rn | head -10
⚠️ 生产警告:MONITOR 会持续占用输出缓冲区,长时间运行可能导致客户端与Redis连接断开。建议单次采集不超过60秒,且优先在只读副本上执行。
3.3 SLOWLOG 与 BIGKEYS 辅助分析
SLOWLOG 虽然不直接反映热点,但热点Key往往伴随高延迟。配置慢查询阈值后,定期检查慢日志可间接发现异常Key。
# 设置慢查询阈值为10毫秒,最多保留128条
CONFIG SET slowlog-log-slower-than 10000
CONFIG SET slowlog-max-len 128
# 查看最近10条慢查询
SLOWLOG GET 10
# 输出示例
1) 1) (integer) 14 # 唯一ID
2) (integer) 1627989123 # 时间戳
3) (integer) 12000 # 执行耗时(微秒)
4) 1) "HGETALL" # 命令
2) "user:profile:9527" # Key
5) "127.0.0.1:6379"
BIGKEYS 扫描使用 --bigkeys 参数,会遍历所有Key并统计每种数据结构的最大Key:
# 执行大Key扫描(建议在从节点或低峰期执行)
redis-cli --bigkeys
# 输出片段
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec...
[00.00%] Biggest string found so far '"session:token:abc123"' with 2048 bytes
[12.50%] Biggest list found so far '"queue:order"' with 15000 items
...
💡 最佳实践:将SLOWLOG与BIGKEYS结合使用——先通过SLOWLOG发现异常延迟的Key,再针对性地用BIGKEYS确认该Key是否为大Key,从而判断热点是否由数据量过大引起。
3.4 客户端统计方案(推荐)
客户端统计是生产环境最推荐的方案,通过在SDK层嵌入计数器,零侵入地统计每个Key的访问频次。以Java的Jedis为例,可借助本地缓存(如Caffeine)实现滑动窗口统计:
// 伪代码:客户端热点统计
public class HotKeyMonitor {
// 滑动窗口:每分钟统计一次,窗口大小60秒
private Cache<String, AtomicLong> counter = Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.SECONDS)
.build();
public void recordAccess(String key) {
AtomicLong count = counter.get(key, k -> new AtomicLong(0));
long current = count.incrementAndGet();
// 阈值判断:单Key QPS > 1000 触发告警
if (current > 1000) {
alert("Hot key detected: " + key + ", QPS: " + current);
}
}
// 在Jedis调用处埋点
public String get(String key) {
recordAccess(key);
return jedis.get(key);
}
}
其他语言的客户端统计思路类似:
- Python (redis-py):使用装饰器或中间件拦截命令调用,利用
collections.Counter做频次统计。 - Go (go-redis):通过
Hook接口实现命令拦截,统计Key访问次数。 - Node.js (ioredis):在
sendCommand方法中注入计数器。
3.5 热点识别架构图
下图展示了四种识别手段在监控体系中的协作关系:
3.6 生产环境组合策略
单一手段无法覆盖所有场景,建议按以下优先级组合:
- 第一道防线(客户端统计):在所有业务SDK中嵌入计数器,实时上报QPS超过阈值的Key。这是零损耗、最精准的方案。
- 第二道防线(SLOWLOG + BIGKEYS):每5分钟拉取慢查询日志,每30分钟在从节点执行大Key扫描,发现潜在热点。
- 第三道防线(MONITOR应急):当告警触发但客户端统计未捕获时,在从节点临时开启MONITOR 30秒,抓取全量命令进行离线分析。
💡 阈值参考:单Key QPS > 5000 或 单Key占用内存 > 10MB 应触发告警。具体阈值需根据实例规格(如8核16GB)和业务容忍度调整。
3.7 避坑指南
| 常见错误 | 后果 | 正确做法 |
|---|---|---|
| 在主节点执行BIGKEYS扫描 | 阻塞主线程,导致业务超时 | 始终在从节点或低峰期执行 |
| MONITOR长时间运行 | 撑爆客户端输出缓冲区,连接断开 | 限制采集时间 ≤ 60秒,使用管道重定向 |
| 仅依赖SLOWLOG判断热点 | 漏掉高QPS但低延迟的Key | 必须结合客户端统计或MONITOR |
| 客户端统计未做本地聚合 | 每个请求都上报,增加网络开销 | 使用滑动窗口本地聚合后批量上报 |
通过上述四种手段的组合,可以构建一套覆盖“实时-准实时-离线”全场景的热点Key识别体系,为后续的削峰与缓存策略提供精准的数据支撑。