- “明明用DEL删了key,监控显示内存一点没降?”去年重构一个日活百万级的feed流系统时,我对着Redis内存监控图百思不得其解——批量清理了20GB的陈旧数据,可用内存居然纹丝不动。直到用
MEMORY USAGE命令深挖,才发现踩中了Redis内存管理的经典暗坑。
现象:删除操作后的“幽灵内存”
场景是这样的:我们需要定期清理用户历史动态的缓存数据。按常理,用Python脚本批量执行DEL命令后,内存应该立刻释放。但实际观测到的现象是:
# 错误姿势:简单循环DEL for key in redis_client.scan_iter("user:feed:*"): redis_client.delete(key) # 执行后内存不降反升!用INFO memory查看内存碎片率(mem_fragmentation_ratio)直接飙到2.5以上——这显然不是正常现象。
根因:内存回收的滞后性与碎片化
这里涉及到Redis的两个核心机制:
DEL命令只是把key标记为“逻辑删除”,实际内存释放要等到后续操作触发或Redis自身内存回收策略执行。用redis-cli --bigkeys配合MEMORY USAGE key命令分析,发现被删除的key中大量是大小不一的hash结构。这正是最坏的情况——离散的大小分布会让内存碎片问题雪上加霜。
解决方案:从暴力DEL到精细治理
错误做法 vs 正确做法
# 错误做法:简单粗暴的循环DEL(产生高碎片) def clear_keys_pattern(pattern): for key in redis_client.scan_iter(pattern): redis_client.delete(key) # 正确做法:分批处理 + 强制内存回收 def clear_keys_safely(pattern, batch=1000): cursor = '0' while cursor != 0: cursor, keys = redis_client.scan(cursor, match=pattern, count=batch) if keys: redis_client.delete(*keys) # 每批处理完主动触发内存回收 redis_client.execute_command("MEMORY PURGE") # 最后强制执行全局回收 redis_client.config_set("activerehashing", "yes")实测对比:在相同数据量下,错误做法会导致内存碎片率长期高于2.0,而正确方案能在1小时内将碎片率压到1.2以下。
避坑清单:DEL命令的正确打开方式
SCAN+DEL替代KEYS+DEL,且控制每次处理的key数量(建议500-1000/批)# 临时设置参数(生产环境慎用) redis-cli config set activerehashing yes redis-cli memory purgeUNLINK替代DEL(Redis 4.0+),其后台线程能减少主线程阻塞redis-cli info memory | grep -E 'used_memory:|mem_fragmentation_ratio:|mem_not_counted_for_evict'总结
Redis的DEL从来就不是“即删即释放”的银弹。下次当你发现删除key后内存居高不下时,不妨先执行这三步:
- 用
MEMORY USAGE确认key是否真被清除 - 检查
mem_fragmentation_ratio是否异常 - 考虑用
UNLINK+MEMORY PURGE组合拳替代单纯DEL
你在处理Redis内存碎片时有什么独门技巧?欢迎分享你的实战经验!