← 中文资源

简体中文版本

Redis — SLOWLOG 被 bigkey 操作刷屏

通过 SLOWLOG 与 LATENCY HISTORY 诊断 bigkey 与阻塞命令造成的 Redis 延迟尖峰,用内存分析定位键,并拆分它们。

阅读英文原文

症状

  慢日志点名操作与代价:HGETALL report:2026-10 一条命令 384 毫秒——单线程模型下,所有其他客户端都排在它后面。用 –bigkeys 找到结构性元凶:三百万字段的单个 hash 就是全部病因。条目里的客户端地址映射到可以停止整体索取的服务。LATENCY HISTORY 的锯齿与报表/批任务对齐、其他客户端的周期性尖峰与之同步,构成时间线证据。

诊断思路

  先读 slowlog get 拿到命令名、时长与客户端地址,识别操作类别;再用 –bigkeys 采样加 memory usage 量化哪些键结构性超标;最后用 latency history 把客户端观测的尖峰与具体命令在时间线上对齐。常见形态:集合/哈希/列表涨到百万级后整体命令原子处理、报表任务业务时段跑 KEYS * 或宽 SMEMBERS、本应是许多键的数据塞进一个键、DEL 大键阻塞主线程整个 free() 时长。

根因

  Redis 在单线程上执行命令,一条处理数百万元素的命令会让所有其他客户端等它的全程。bigkey 放大了这个 O(n) 成本;阻塞式整体操作(KEYS、SMEMBERS、HGETALL、大键 DEL)把结构性膨胀变成周期性延迟尖峰。

修复与验证

  整体读取换成游标迭代(SSCAN/HSCAN 配 count=500);写侧就把结构分桶——按天一个 hash 而不是按月,让键天然有界;两个永久替换:大键删除用 UNLINK(后台释放),应用代码里的 KEYS 一律换 SCAN——定时任务里的 KEYS 就是一场排期好的宕机。验证时同等负载下 SLOWLOG 保持为空、LATENCY HISTORY 无 command 事件、客户端 p99 回到基线。注意 SSCAN 遇到变化中的键可能重复或漏项,扫描型任务要幂等并容忍轻微漂移。

代码示例

redis-cli slowlog get 3
1) 1) (integer) 14
   2) (integer) 1729584000
   3) (integer) 384112          <- 384 ms
   4) 1) "HGETALL"
      2) "report:2026-10"
redis-cli --bigkeys -i 0.01
# Sampled 100000 keys
# Biggest hash found 'report:2026-10' has 3120000 fields
cursor = 0
while True:
    cursor, batch = r.hscan("report:2026-10", cursor=cursor, count=500)
    process(batch)
    if cursor == 0:
        break
# one hash per day instead of one hash per month:
key = f"report:{day:%Y-%m-%d}"
r.hset(key, field, value)