redis Can’t save in background: fork: Cannot allocate memory 解决方法

  • java日志中报错
redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
    at redis.clients.jedis.Protocol.processError(Protocol.java:66) ~[jedis-2.2.1.jar:na]
    at redis.clients.jedis.Protocol.process(Protocol.java:73) ~[jedis-2.2.1.jar:na]
    at redis.clients.jedis.Protocol.read(Protocol.java:138) ~[jedis-2.2.1.jar:na]
    at redis.clients.jedis.Connection.getIntegerReply(Connection.java:191) ~[jedis-2.2.1.jar:na]
    at redis.clients.jedis.Jedis.incr(Jedis.java:560) ~[jedis-2.2.1.jar:na]
  • redis日志中报错1:
Can't save in background: fork: Resource temporaily unavailable
  • redis日志报错2:
Can’t save in background: fork: Cannot allocate memory

原因是因为,redis有个默认的选项:

stop-writes-on-bgsave-error yes

这个选项默认情况下,如果在RDB snapshots持久化过程中出现问题,设置该参数后,Redis是不允许用户进行任何更新操作。

不彻底的解决方法是:将这个选项改为false:

stop-writes-on-bgsave-error false

但是这样只是当redis写硬盘快照出错时,可以让用户继续做更新操作,但是写硬盘仍然是失败的;

彻底的解决方法:

  • 编辑文件/etc/sysctl.conf,添加:
vm.overcommit_memory=1

然后执行下列命令,使其生效:

sysctl -p

vm.overcommit_memory 这个参数又是干什么的呢?
Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存,将这些不会使用的空闲内存分配给其它程序使用,以提高内存利用率,这种技术叫做Overcommit。一般情况下,当所有程序都不会用到自己申请的所有内存时,系统不会出问题,但是如果程序随着运行,需要的内存越来越大,在自己申请的大小范围内,不断占用更多内存,直到超出物理内存,当linux发现内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程,哪些占用内存越多,运行时间越短的进程越有可能被杀掉),以便释放内存。

参考博文:https://blog.csdn.net/zqz_zqz/article/details/53384854

如果还不能解决,那么进行以下步骤:
在安装redis的服务器上,使用命令登录redis:

redis-cli

然后输入配置的用户名和密码(我的是:auth/123456)
查看redis内存占用情况:

info
# Memory
# 数据占用了多少内存(字节 byte)
used_memory:13490096 
# 数据占用了多少内存(带单位的,可读性好)
used_memory_human:12.87M 
# redis占用了多少内存
used_memory_rss:13490096
# 占用内存的峰值(字节)  
used_memory_peak:15301192 
# 占用内存的峰值(带单位的,可读性好)
used_memory_peak_human:14.59M 
# lua引擎所占用的内存大小(字节)
used_memory_lua:31744  
# 内存碎片率
mem_fragmentation_ratio:1.00
# redis内存分配器版本,在编译时指定的。有libc、jemalloc、tcmalloc这3种。
mem_allocator:libc 

看 used_memory就行了;

根据内存占用情况,编辑redis配置文件(我的是/etc/redis.conf),修改文件中对应的最大内存大小(537行)和策略(560行)以小编的为例:

# 537行修改后为:
maxmemory 6GB

# 560行修改后为:
maxmemory-policy allkeys-lru

然后重启redis即可:

service redis restart

redis占用内存满了的解决方法

1. 增加内存

2. 采用内存淘汰策略

  • redis内存淘汰策略:当redis内存达到最大的内存限制会申请额外的内存空间。对于怎么处理需要新写入且需要申请额外空间的数据?这时候就需要采用内存淘汰策略了。

    • noeviction(默认策略):当内存不足以容纳新写入数据时,新写入操作会报错。
    • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
    • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
    • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
    • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
    • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。
  • 推荐两种算法方案:

    • LRU(最近最少使用淘汰算法(Least Recently Used))
      LRU是淘汰最长时间没有被使用的数据。其核心思想就是“如果数据最近被访问过,那么将来被访问的机率也更高”。基本思路:如果最近使用得比较多的数据就把他放到列表头部,依次更新,从列表尾部的依次淘汰,就是删除对应的key。
    • LFU(最不经常使用淘汰算法(Least Frequently Used))
      LFU是淘汰一段时间内,使用次数最少的数据。它是基于“如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小”的思路。
      在这里插入图片描述

3. 使用redis集群

参考博客:https://blog.csdn.net/weixin_44655002/article/details/97489990

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章