Redis驱逐频繁主因是maxmemory过小或Value过大,表现为evicted_keys激增、used_memory_peak逼近maxmemory;应通过--bigkeys定位大Key、压缩/拆分Value、校验去重写入,并监控evicted_keys增速与used_memory_dataset_perc是否收敛。

Redis 驱逐频繁,大概率是 maxmemory 设置过小或 Value 过大
Redis 启动时若配置了 maxmemory(比如 2GB),而业务持续写入大 Value(如序列化后的用户画像、HTML 片段、Base64 图片),内存很快触顶,就会触发 maxmemory-policy 定义的驱逐策略(如 allkeys-lru)。这不是“缓存淘汰正常现象”,而是内存压力已失控的信号——尤其当 evicted_keys 指标每秒增长数十次,同时 used_memory_peak 接近 maxmemory,基本可断定是 Value 尺寸和写入频次共同导致的恶性循环。
实操建议:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
redis-cli --stat实时观察evicted_keys和used_memory_human变化节奏,确认是否集中在某类 key 上 - 通过
redis-cli --bigkeys扫描,定位 >1MB 的 key;注意它只采样,需配合MEMORY USAGE <key></key>精确验证 - 检查业务日志中是否在高频调用
SET或HSET写入含大量字段的 Hash(例如一次写入 500 个用户标签)
大 Value 写入本身会放大内存开销与阻塞风险
一个 5MB 的字符串 Value,在 Redis 中实际占用不止 5MB:RDB/AOF 持久化时需完整拷贝;主从同步时整块传输;如果启用了 lazyfree-lazy-eviction yes,驱逐时虽不阻塞主线程,但后台线程释放内存仍需时间。更隐蔽的问题是,大 Value 会让 INFO memory 中的 mem_fragmentation_ratio 异常升高(>1.5),说明内存碎片严重,进一步加剧驱逐频率。
实操建议:
- 禁止直接存 Base64 图片、JSON 数组(>100KB)、未压缩的 HTML —— 这些应转存对象存储,Redis 只存 URL 或 ID
- Hash 类型慎用
HSET key field value单字段写入大内容;改用分片:按业务维度拆成user:123:profile:part1、user:123:profile:part2 - 对必须缓存的大结构(如推荐列表),先用
zstd或snappy压缩再存,读取时解压;注意压缩/解压耗时是否可接受
降低写入频次的关键是识别并拦截无效/重复写入
很多驱逐风暴并非来自真实业务增长,而是代码缺陷:比如定时任务每 10 秒全量刷新用户缓存,即使用户数据没变也强制 SET;或接口幂等性缺失,前端重试导致同一份大 Value 被反复写入。这类写入既无业务价值,又直接消耗内存配额。
实操建议:
- 在写入前加一层轻量比对:用
GET <key></key>读旧值,MD5或crc32校验新旧内容是否一致,仅不同时才SET - 对定时刷新场景,改用「变更驱动」:监听数据库 binlog 或消息队列,只在数据真正更新时触发缓存更新
- 给高频写入 key 加监控告警,例如用
MONITOR抓包分析 5 分钟内SET user:*的调用来源,定位 SDK 或中间件的滥用行为
业务逻辑改造后必须验证驱逐是否真正收敛
改完代码、调大 maxmemory 或加压缩,不代表问题解决。要盯住两个指标:一是 evicted_keys 增速是否归零或降至个位数/分钟;二是 used_memory_dataset_perc(实际数据占比)是否稳定在 70%–85%,长期低于 60% 说明仍有冗余或冷数据未清理。
容易被忽略的点:
-
maxmemory-policy设为noeviction不是解法——它会让写入直接报错(error) OOM command not allowed when used memory > 'maxmemory'.,业务更不可控 - 集群模式下,单个 slot 的大 Value 会导致该节点内存独占飙升,其他节点空闲,此时横向扩容无效,必须先做 Value 拆分
- 客户端 SDK(如 Jedis/Lettuce)若开启
pool且maxTotal过小,可能因连接等待间接拉长写入耗时,掩盖真实瓶颈

















