当mem_fragmentation_ratio>1.5时,即使used_memory未达maxmemory,因内存碎片导致malloc失败,redis会提前触发淘汰;此时used_memory_rss居高不下,淘汰后rss不降反加剧碎片,形成恶性循环。

used_memory 和 used_memory_rss 差太多,淘汰会提前触发
Redis 的 maxmemory 限制只和 used_memory 比较,但操作系统真正能分配的内存取决于 used_memory_rss。当 mem_fragmentation_ratio(即 used_memory_rss / used_memory)超过 1.5,说明 jemalloc 留了一堆小碎片没还给 OS;此时即使 used_memory 还差 200MB 才到 maxmemory,used_memory_rss 可能已经撞上容器或系统内存上限,导致 malloc 失败——Redis 会立刻触发淘汰,哪怕还没到配置的水位。
常见现象:
- INFO memory 显示
used_memory:3.8G,maxmemory:4G,看起来还有余量,但 key 开始被删 -
mem_fragmentation_ratio持续在 1.8~2.5 之间波动 -
evicted_keys在涨,而keyspace_hits没明显下降 → 不是业务热点变化,是“被迫淘汰”
为什么 allkeys-lru 淘汰后 RSS 不降,反而更容易再触发淘汰
淘汰 key 只是把对应数据结构标记为可复用,并通知 jemalloc 这块内存空闲了;jemalloc 默认不立即归还给 OS,而是留着下次分配复用。结果就是:used_memory 下降了,used_memory_rss 几乎不动,mem_fragmentation_ratio 更高了。
这形成恶性循环:碎片越积越多 → 实际可用连续内存越少 → 下次 malloc 更容易失败 → 更早触发淘汰 → 更多 key 被删 → 更多小块空闲内存堆积。
实操建议:
- 别只盯着
evicted_keys增长就调大maxmemory,先查mem_fragmentation_ratio - Redis 4.0+ 可开
CONFIG SET activedefrag yes,但要配好active-defrag-threshold-lower(默认 10,建议设为 20~30)和active-defrag-cycle-min(避免卡主进程) - 紧急时直接执行
MEMORY PURGE(仅 jemalloc 支持),比等自动整理快得多
volatile-* 策略在碎片高时可能完全失效
如果用了 volatile-lru 或 volatile-ttl,但大部分 key 没设 TTL,那真正能参与淘汰的 key 很少。当 used_memory_rss 高到触发 malloc 失败时,Redis 仍会尝试淘汰——但它只能从那少量带 TTL 的 key 里挑,挑完就只能退回到 noeviction 行为:写命令开始报 (error) OOM command not allowed when used memory > 'maxmemory'。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
验证方式很简单:
-
redis-cli INFO stats | grep expired_keys—— 如果长期几乎不增长,说明过期键清理本身就不活跃 -
redis-cli INFO keyspace | grep -E "db[0-9]+:"看各 db 中带过期时间的 key 数量占比 - 对比
evicted_keys和expired_keys的增速:前者远大于后者,说明淘汰主力不是过期机制,而是 maxmemory 触发的强制淘汰
主从节点因碎片率差异导致淘汰时机错开
同一套配置(maxmemory 4gb + allkeys-lfu),主从的 used_memory 可能很接近,但 mem_fragmentation_ratio 经常不同:从节点若刚完成 RDB 加载或 AOF rewrite,碎片率可能瞬间冲到 2.0+,而主节点还在 1.2 左右。结果就是从节点更早触发淘汰,删掉一些主节点还留着的 key。
这不是配置错误,是内存分配器行为不可控导致的客观偏差。生产环境必须接受这点,并规避依赖从库强一致读的场景。
关键点:
- 不要用
WAIT来“保证”从库淘汰同步——它只保传播,不保执行 - 对库存、订单等关键 key,读操作必须走主节点,或用业务层双写+消息清缓存兜底
- 监控不能只看
repl_offset差值,得加sync_probe:ts时间戳探测,才能发现“已同步但未执行”的延迟
碎片问题藏得深,used_memory 看着安全不代表真安全;淘汰策略只是“删谁”的逻辑,不是“还内存”的开关。










