当前位置: 首页>后端>正文

spring cloud gateway redis 内存溢出 redis堆外内存溢出

现象描述:

redis5.0.5集群要对集群进行扩容,先扩从节点,由于是docker swarm管理的镜像启动,策略是一直重启,产生以下几点现象:

1.当从节点没有启动起来并且每次重启都会加载出一个core.xxxx文件,文件大小与dump和aof文件同大小

2.Redis aborting for OUT OF MEMORY   及  Out Of Memory allocating 184 bytes!

3.Can't attach the replica to the current BGSAVE. Waiting for next BGSAVE for SYNC

Backtrace:

------ INFO OUTPUT ------

8:S 27 Mar 2020 23:19:52.787 # Out Of Memory allocating 184 bytes!

8:S 27 Mar 2020 23:19:52.787 # ------------------------------------------------

8:S 27 Mar 2020 23:19:52.787 # !!! Software Failure. Press left mouse button to continue

8:S 27 Mar 2020 23:19:52.787 # Guru Meditation: Redis aborting for OUT OF MEMORY #server.c:3893

8:S 27 Mar 2020 23:19:52.787 # (forcing SIGSEGV in order to print the stack trace)

8:S 27 Mar 2020 23:19:52.787 # ------------------------------------------------

/usr/local/bin/redis-cluster-entrypoint.sh: line 12: 8 Segmentation fault (core dumped) redis-server /data/redis.conf
8:M 27 Mar 2020 23:57:48.300 * Can't attach the replica to the current BGSAVE. Waiting for next BGSAVE for SYNC

8:M 27 Mar 2020 23:58:22.080 # Connection with replica 10.19.185.17:8616 lost.

8:M 27 Mar 2020 23:58:27.444 * Replica 10.19.185.17:8616 asks for synchronization

8:M 27 Mar 2020 23:58:27.444 * Partial resynchronization not accepted: Replication ID mismatch (Replica asked for '72d20b6a626dc6b83eba77ec7a59f68bf3049856', my replication IDs are '6b4904558bc9e5e5d4d245dab835be2c31b4d82f' and '0000000000000000000000000000000000000000')

 解决方案:

解决步骤1.曾尝试更改redis.conf的配置

默认值:client-output-buffer-limit 256mb 64mb 60 
如果主节点创建和传输RDB的时间过长,对于高流量写入场景非常容易造成主节点复制客户端缓冲区溢出,
如果60s内缓冲区消耗持续大于64MB或者直接超过256MB,主节点直接关闭复制客户端连接,造成全量同步数据失败

config set client-output-buffer-limit "slave 0 0 0" 
尝试更改上边配置,对加载到缓冲区的数据量不做时间和量的限制,但是实际监控显示,
也不会超过这个时间和数据量,所以这个的影响只是一方面的,更改过后,也没有解决问题,设置回原参数

解决步骤2.更改系统参数vm.overcommit_memory=1

Redis的数据回写机制分同步和异步两种,

同步回写即SAVE命令,主进程直接向磁盘回写数据。在数据大的情况下会导致系统假死很长时间,所以一般不是推荐的。
异步回写即BGSAVE命令,主进程fork后,复制自身并通过这个新的进程回写磁盘,回写结束后新进程自行关闭。由于这样做不需要主进程阻塞,系统不会假死,一般默认会采用这个方法。
内存中的热数据随时可能修改,要在磁盘上保存某个时间的内存镜像必须要冻结。冻结就会导致假死。fork一个新的进程之后等于复制了当时的一个内存镜像,这样主进程上就不需要冻结,只要子进程上操作就可以了。

在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢?肯定会报内存无法分配的。更可气的是,越是改动频繁的主机上fork也越频繁,fork操作本身的代价恐怕也不会比假死好多少。
因为以上原因提出修改系统参数解决方案:Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。

vm.overcommit_memory = 1,直接放行
vm.overcommit_memory = 0:则比较此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。
vm.overcommit_memory = 2:则会比较进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行

有三种方式修改内核参数(root权限):
1.vi /etc/sysctl.conf ,vm.overcommit_memory=1,执行sysctl -p使配置文件生效  #永久,重启之后,仍然生效
2.执行 sysctl vm.overcommit_memory=1 或 sysctl -w vm.overcommit_memory=1    #临时,重启之后,恢复为原参数值
3.执行echo 1 > /proc/sys/vm/overcommit_memory   #临时,重启之后,恢复为原参数值

修改完成后,再次尝试主从同步:4分钟左右完成8G数据量的同步

8:M 28 Mar 2020 00:32:46.468 * Starting BGSAVE for SYNC with target: disk

8:M 28 Mar 2020 00:32:46.749 * Background saving started by pid 221

221:C 28 Mar 2020 00:36:42.943 * DB saved on disk

8:M 28 Mar 2020 00:36:43.380 * Background saving terminated with success

参考文章:https://www.linuxidc.com/Linux/2012-07/66079.htm


https://www.xamrdz.com/backend/3dm1922037.html

相关文章: