事情本身不复杂,线索都在日志里。CentOS 7.9 上跑 Redis 6.2,4 核 8G,maxmemory 设成 4gb,业务写 hash 时一直报 OOM command not allowed when used memory > ‘maxmemory’,可 info memory 里 used_memory 只有 2.1G,碎片率显示 1.82。
第一反应是「淘汰策略是 noeviction,一旦判定超限就直接拒绝写命令,不腾空间」,验证下来不成立。
真正麻烦的地方在于,几个原因的现象几乎一样。大量 key 过期或被删之后,jemalloc 把空闲页留在自己的 arena 里,不还给操作系统。少数情况下是RSS 被算进内存上限,used_memory 没到但进程实际占用已经顶到 maxmemory。
不容易想到的是,活动碎片整理没开,长期反复增删的实例碎片只会越来越高。
动手时先分清是数据多还是碎片多
redis-cli info memory | grep -E 'used_memory_human|used_memory_rss_human|mem_fragmentation_ratio'
接着把活动碎片整理打开并设定触发阈值
redis-cli config set activedefrag yes && redis-cli config set active-defrag-ignore-bytes 100mb && redis-cli config set active-defrag-threshold-lower 10
保守起见先换成会腾空间的淘汰策略
redis-cli config set maxmemory-policy allkeys-lru
剩下的就是观察碎片率与 RSS 是否真的往下走
redis-cli info memory | grep -E 'mem_fragmentation_ratio|defrag_running'
改完先别撤,确认这几项。mem_fragmentation_ratio 降到 1.3 以下,defrag_running 归零,写入不再报 OOM,RSS 与 used_memory 的差值收敛到几百 M 以内。
提醒一点。整理碎片要消耗 CPU,业务高峰期别开;改 config set 只在当前进程有效,配置文件和运维平台两处都要落。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。
