Redis内存溢出问题排查
最近生产环境服务器上的redis内存波动,导致了一次OOM,查询/var/log/messages
后发现原本只会在1~2G大小之间波动的Redis内存竟然达到8G,然后OOM被主动Kill。
因为过年期间并没有更新过代码,所以一直完好运行的程序应该不会出现大的BUG去大量写入数据到Redis。于是检查起Redis配置(redis_version:3.2.10)。
设置 maxmemory
查看了一下正在运行的Redismaxmemory
为0
1 | 127.0.0.1:6379> CONFIG GET maxmemory |
设定一个合理的最大使用量避免OOM,我这边根据业务实际情况设置成2G
1 | 127.0.0.1:6379> CONFIG SET maxmemory 2G |
另外在/etc/redis.conf
设置maxmemory 2G
刷新策略
观察服务器内存碎片是否过高,公式如下
1 | mem_fragmentation_ratio=used_memory_rss/used_memory |
当值大于1时表明有内存碎片,越大越多。小于1代表正在使用虚拟内存(使用磁盘),需要增加内存。
值在1~1.5之间属于较好范围。我观察到服务配置中使用的是默认的永不过期策略
1 | 127.0.0.1:6379>config get maxmemory-policy |
虽然我都有指定redis数据的过期时间,但还是发生oom,我就把策略设成volatile-lru
策略名 | 说明 |
---|---|
noeviction | 默认策略,不进行置换,没有内存时新增命令都会返回error |
volatile-lru | 从设置过期时间的Key中选取不常使用数据删除 |
allkeys-lru | 优先删除掉最近最不经常使用的Key |
allkeys-random | 随机删除Key |
volatile-random | 随机删除设置过期时间的Key |
volatile-ttl | 从设置过期时间Key删除TTL最短的 |
1 | - 当所有key没有指定过期时间时,用` allkeys-lru`删除不常用的key |
LRU 中取出多少匹配数目Key由maxmemory-samples
控制,这里我们用默认的5就好了。
备注
名称 | 说明 |
---|---|
used_memory | 已经使用了的内存大小,单位byte |
used_memory_rss | redis物理内存的大小 |
used_memory_peak | redis内存使用的峰值 |
used_memory_lua | lua脚本所占用的内存 |
mem_fragmentation_ratio | 内存碎片率 |
total_system_memory | 系统内存大小 |
maxmemory | 内存限制大小最大值 |
maxmemory_policy | 过期策略 |
依然OOM
隔天上午Redis服务又挂了,查看信息
1 | # dmesg -T | grep redis |
- total-vm 进程共使用的虚拟内存
- anon-rss 虚拟内存占实际物理内存
- file-rss 虚拟内存占磁盘空间
显然内存大小已经超过了我之前设置的2G,过期策略也没有执行到。
后来查阅到,当Redis开启RDB功能时,Redis自身是通过fork子进程来处理RDB文件。当系统overcommit_memory
值为0时,fork需要父进程使用的内存大小进行copy-on-write, 只要剩余空间没有足够,就会失败。设置为1就能允许分配所有内存。
很遗憾,看了一下/proc/sys/vm/overcommit_memory
确实已经设置为1了。
没办法只能让总监升级主机内存,并且redis程序让supervisor管理,方便自动重启
本文发表于 2020-03-08,最后修改于 2020-04-04。
本站永久域名「 blog.amoyiki.com 」,也可搜索「 四畳半神话大系 」找到我。
期待关注我的 ,查看最近的文章和动态。