Redis 大 Key 与热 Key 排查治理实战:从发现、拆分到安全删除

举报
yd_229207802 发表于 2026/10/24 10:27:39 2026/10/24
【摘要】 前言Redis 用久了,几乎每个团队都会踩到“大 Key”和“热 Key”的坑:某个实例内存突然告警、某个分片 CPU 打满而其他分片很闲、一次 DEL 让业务卡顿好几百毫秒。这类问题的共同点是平时看不出来,出事时影响很大。本文把我在华为云分布式缓存服务 DCS(Redis)和自建 Redis 上排查、治理大 Key 与热 Key 的步骤整理成一套流程:先定义标准,再发现、再定位来源、最后拆...

前言

Redis 用久了,几乎每个团队都会踩到“大 Key”和“热 Key”的坑:某个实例内存突然告警、某个分片 CPU 打满而其他分片很闲、一次 DEL 让业务卡顿好几百毫秒。这类问题的共同点是平时看不出来,出事时影响很大。本文把我在华为云分布式缓存服务 DCS(Redis)和自建 Redis 上排查、治理大 Key 与热 Key 的步骤整理成一套流程:先定义标准,再发现、再定位来源、最后拆分和安全删除。每一步都附上可以直接执行的命令或代码。

一、先统一“多大算大、多热算热”

没有标准就没法治理。我们团队采用的阈值如下,大家可以按业务规模调整:

  • String 类型 value 超过 10 KB;
  • Hash、List、Set、ZSet 元素个数超过 5000,或总大小超过 10 MB;
  • 单个 Key 的访问 QPS 超过实例总 QPS 的 10%,或单 Key 每秒访问超过 5000 次,视为热 Key。

阈值写进团队规范后,代码评审和告警都能对齐同一个口径,后面的工具输出也能直接按这个标准过滤。

二、发现大 Key:控制台分析与命令行扫描结合

DCS 控制台的“缓存分析”里提供了大 Key 分析和热 Key 分析,可以手动触发,也可以配置定时任务。分析基于 SCAN 实现,对线上影响较小,建议在业务低峰期每天跑一次,把结果作为日常巡检的一部分。

自建实例或者需要更灵活的筛选时,可以用 redis-cli 自带的扫描:

# 按类型统计最大的 Key,-i 0.01 表示每 100 次 SCAN 休眠 10ms,降低对线上的压力
redis-cli -h 127.0.0.1 -p 6379 -a '******' --bigkeys -i 0.01

# Redis 6.0 以上可以按内存占用统计
redis-cli -h 127.0.0.1 -p 6379 -a '******' --memkeys -i 0.01

--bigkeys 只给出每种类型最大的一个 Key,信息不够时,我会用一段 Python 脚本按阈值把所有超标 Key 列出来:

import redis

r = redis.Redis(host="127.0.0.1", port=6379, password="******")
LIMIT_BYTES = 10 * 1024 * 1024
LIMIT_ITEMS = 5000
LEN_CMD = {"hash": r.hlen, "list": r.llen, "set": r.scard, "zset": r.zcard}

for key in r.scan_iter(count=500):
    t = r.type(key).decode()
    size = r.memory_usage(key, samples=0) or 0
    items = LEN_CMD[t](key) if t in LEN_CMD else 1
    if size > LIMIT_BYTES or items > LIMIT_ITEMS or (t == "string" and size > 10240):
        print(t, key.decode(errors="ignore"), size, items)

注意 MEMORY USAGE 带 samples=0 会遍历全部元素,对超大集合本身就有开销,第一次跑可以先去掉这个参数,用默认采样值粗筛,再对可疑 Key 精确计算。

三、发现热 Key:看分布,再看具体 Key

热 Key 的典型表现是集群实例中某个分片的 CPU、带宽明显高于其他分片。先在监控里按分片对比“CPU 使用率”和“网络输入/输出流量”,锁定异常分片,再找具体 Key:

# 需要将 maxmemory-policy 设置为 LFU 类策略(allkeys-lfu 或 volatile-lfu)
redis-cli -h 127.0.0.1 -p 6379 -a '******' --hotkeys

# 临时抓取几秒命令流,按 Key 统计出现次数(只建议在测试或低峰期短时间使用)
timeout 5 redis-cli -a '******' monitor | awk '{print $5}' | sort | uniq -c | sort -rn | head -20

MONITOR 会显著增加实例负载,生产环境我更推荐在客户端侧统计:在 Redis 访问封装层里按 Key 计数,每分钟上报 Top N,既不影响服务端,也能直接定位到是哪个服务、哪段代码在访问。

四、治理大 Key:拆分是根本

找到大 Key 后,按类型选择拆分方式:

  • 大 String:如果是序列化后的大对象,先看是否所有字段都需要,按读取场景拆成多个小 Key;如果只是存储大文本,考虑压缩或者放到对象存储 OBS,Redis 里只存地址。
  • 大 Hash:按 field 做哈希分桶,例如 user:profile:{bucket},bucket = crc32(field) % 64,读写时先算桶号。
  • 大 List / ZSet:按时间或分数区间分段,例如排行榜按日期拆成 rank:20261024,查询历史时再合并。

分桶示例:

import zlib

BUCKETS = 64

def bucket_key(base, field):
    return f"{base}:{zlib.crc32(field.encode()) % BUCKETS}"

def hset_split(r, base, field, value):
    r.hset(bucket_key(base, field), field, value)

def hget_split(r, base, field):
    return r.hget(bucket_key(base, field), field)

五、安全删除:不要直接 DEL

拆分完成后,旧的大 Key 需要删除。直接 DEL 一个百万元素的集合会阻塞主线程,Redis 4.0 以上优先使用异步删除:

UNLINK big:hash:key

如果版本较老,就用 SCAN 类命令分批删除,例如 Hash 每次删 500 个 field:

cursor = 0
while True:
    cursor, data = r.hscan("big:hash:key", cursor, count=500)
    if data:
        r.hdel("big:hash:key", *data.keys())
    if cursor == 0:
        break
r.delete("big:hash:key")

另外建议开启 lazyfree-lazy-expire 和 lazyfree-lazy-eviction,避免大 Key 过期或被淘汰时同步释放内存造成卡顿。

六、治理热 Key:分散和前置

热 Key 的思路是把集中访问分散开,或者干脆不让请求打到 Redis:一是在应用内加本地缓存(如 Caffeine),设置 1 到 5 秒的短过期,扛住瞬时峰值;二是把热 Key 复制成多份,例如 hot:item:1001:0 到 hot:item:1001:7,读时随机选一份,写时全部更新;三是对读多写少的场景,使用读写分离实例,把读流量分到只读副本。

七、把检查放进日常流程

工具和方案准备好之后,真正决定效果的是能否持续执行。我们的做法有三条:第一,在代码评审清单里加入“新增 Redis Key 是否评估过元素上限和过期时间”,从源头避免集合无限增长;第二,把控制台缓存分析的结果每天推送到团队群,超过阈值的 Key 自动创建跟踪任务,指定负责人和处理期限;第三,大促或活动上线前,用压测流量预演一次热 Key 场景,提前确认本地缓存和多副本方案是否生效。坚持一段时间后,排查工作会从“出事再查”变成“例行巡检”,值班压力明显下降。

总结

大 Key 和热 Key 的治理,难点不在命令本身,而在于形成闭环:定好阈值、定期扫描、找到来源、拆分改造、安全删除,最后把检查项加进代码评审。按这个流程做下来,我们的实例再没有出现过因单个 Key 导致的分片 CPU 告警,内存使用也更加平稳。希望这套步骤对正在使用 DCS 或自建 Redis 的同学有所帮助。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。