用单容器 Redis 制造热 Key 访问,练习用 LFU、MONITOR 和 commandstats 定位

演练目标

环境准备

安装 Docker,本机 6380 端口空闲。必须启用 LFU 淘汰策略,redis-cli --hotkeys 才能工作。

docker run -d --name lab-redis -p 6380:6379 redis:7-alpine \
  redis-server --maxmemory 64mb --maxmemory-policy allkeys-lfu
until docker exec lab-redis redis-cli ping >/dev/null 2>&1; do sleep 1; done
docker exec lab-redis redis-cli SET hot:sku:1001 'sku-1001-value'
docker exec lab-redis redis-cli CONFIG GET maxmemory-policy

如果 maxmemory-policy 不是 allkeys-lfu,--hotkeys 会直接报错,这是常见的准备阶段问题。

注入故障

在容器内生成 50 万条针对同一个 key 的 GET,通过 redis-cli --pipe 批量发送:

awk 'BEGIN { for (i = 0; i < 500000; i++) print "GET hot:sku:1001" }' \
  | docker exec -i lab-redis redis-cli --pipe > /tmp/lab-redis-pipe.log 2>&1 &
sleep 1
docker stats --no-stream lab-redis
wait
cat /tmp/lab-redis-pipe.log

预期 Redis 容器 CPU 明显升高,单线程主循环接近打满一个核;--pipe 日志显示发送和接收的命令数量。50 万条命令可能很快结束,CPU 采样要趁压测仍在运行时执行。

观察现象

docker exec lab-redis redis-cli INFO commandstats | grep -E 'cmdstat_get|cmdstat_set'
docker exec lab-redis timeout 3 redis-cli monitor | head -20
docker exec lab-redis timeout 5 redis-cli --latency
docker exec lab-redis redis-cli --hotkeys
docker exec lab-redis redis-cli --bigkeys
docker exec lab-redis redis-cli STRLEN hot:sku:1001

预期 MONITOR 连续输出同一条 GET hot:sku:1001;--hotkeys 把该 key 列为高频访问;commandstats 中 cmdstat_get 的调用次数远高于其他命令;STRLEN 很小,说明它不是大 Key;--latency 可能升高,也可能仍然很低,取决于压测是否已经结束。

判断与定位

  1. 热 Key 的特征是访问次数集中,不是 value 大小。用 --hotkeys、MONITOR 和 commandstats 互相印证。
  2. 大 Key 用 --bigkeys、STRLEN、LLEN、HLEN 判断。大 Key 主要消耗内存、网络和单次操作时间,热 Key 主要消耗 CPU 和连接带宽。
  3. SLOWLOG 为空不代表没有问题。热 Key 上的 GET 通常单次很快,不会进入慢日志,但高频访问会把单核打满。
  4. 容易误判:Redis 是单线程处理命令,top 中 100% 只代表一个核,整机 CPU 可能看起来不高;另一个误判是认为集群模式下热 Key 会自动分散,实际上同一个 key 永远落在同一个分片。
  5. MONITOR 本身会显著增加开销,只能在短时间窗口使用,不要在生产长期开启。

修复

停止压测并清理热 Key,验证 CPU 恢复:

docker exec lab-redis redis-cli DEL hot:sku:1001
docker exec lab-redis redis-cli --latency
docker stats --no-stream lab-redis

真实修复不能只删 key。常见手段包括:应用本地缓存、把热 Key 拆成带随机后缀的多个子 Key 并随机读取、读写分离、对热点请求限流、对大 Key 拆分并用 HSCAN/SSCAN 分批访问。集群场景还要检查分片键设计,避免流量集中到单个分片。

清理与回滚

docker rm -f lab-redis
rm -f /tmp/lab-redis-pipe.log

容器删除后数据和配置全部消失。若压测进程仍在运行,删除容器会让管道因连接断开而结束;必要时用 jobs 查看并等待后台任务退出。

复盘

延伸阅读

读完自测

  1. 为什么 redis-cli --hotkeys 在默认配置下可能直接报错?
  2. 热 Key 和大 Key 的主要区别是什么?
  3. 为什么 SLOWLOG 为空仍可能是热 Key 问题?
答案
  1. --hotkeys 依赖 LFU 淘汰策略,默认的 noeviction 或其他策略不支持,需要设置 maxmemory-policy allkeys-lfu。
  2. 热 Key 是访问频率集中,大 Key 是单个 value 或集合过大;前者主要耗 CPU,后者主要耗内存、网络和单次操作时间。
  3. 热 Key 上的单条命令通常执行很快,不会超过慢日志阈值,但高频访问仍会打满单核。