2022-03-09 10:19:12
Redis 大 key 问题可通过识别、定位和安全删除三个步骤处理,核心在于避免阻塞主线程并减少对系统性能的影响。 以下是具体解决方案:
一、大 key 的定义与影响String 类型:值大小超过 10 KB。
集合类型(Hash/List/Set/ZSet):元素数量超过 5000 个。
客户端阻塞:Redis 单线程执行命令,操作大 key 会导致长时间阻塞,引发客户端超时。
网络拥塞:频繁访问大 key 会产生高流量(如 1MB key 每秒 1000 次访问产生 1GB/s 流量),可能压垮千兆网卡。
内存倾斜:集群模式下,大 key 集中于部分节点,导致内存和查询分布不均。
删除阻塞:直接使用 DEL 命令删除大 key 会阻塞主线程,影响后续请求处理。
优先在从节点执行,避免阻塞主节点;若无从节点,需在低峰期运行。
使用 -i 参数控制扫描间隔(如 -i 0.1 表示每 100ms 扫描一次)。
仅返回每种类型中最大的 key,无法获取前 N 名。
集合类型仅统计元素数量,不计算实际内存占用(如元素小但数量多时可能误判)。
通过 SCAN 遍历所有 key,用 TYPE 获取类型。
对 String 类型使用 STRLEN 获取字节数。
对集合类型:
若已知元素平均大小,用 LLEN/HLEN/SCARD/ZCARD 获取数量后计算内存。
若未知元素大小,使用 MEMORY USAGE(Redis 4.0+)直接查询内存占用。
Hash:用 HSCAN 分批获取字段,再用 HDEL 逐个删除。
def del_large_hash(r, key, batch_size=100): cursor = '0' while cursor != 0: cursor, data = r.hscan(key, cursor=cursor, count=batch_size) for field in data: r.hdel(key, field[0])List:用 LTRIM 保留前 N 个元素,逐步截断。
def del_large_list(r, key, batch_size=100): while r.llen(key) > 0: r.ltrim(key, 0, -batch_size - 1)Set/ZSet:用 SSCAN/ZSCAN 分批扫描,再用 SREM/ZREMRANGEBYRANK 删除。
避免存储大 key,拆分数据(如将大 Hash 拆分为多个小 Hash)。
对大 List/Set 使用压缩或分片存储。
定期扫描大 key 并设置阈值告警(如内存超过 1MB 或元素超过 1000 个)。
限制大 key 的访问频率,避免突发流量冲击。
通过以上方法,可有效识别、定位和安全删除 Redis 大 key,保障系统稳定性和性能。