最近将一个项目部署到了腾讯云上,项目里用了redis做数据缓存。运行了三天都没有什么问题,但是到了第四天我进入网站某个页面时出现了bug,截图如下

org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

异常里面显示无法连接上jedis ,第一时间我去查看服务器上redis的运行情况,发现redis仍然是在运行中的,然后当我想ping一下redis测试一下的时候,出现了以下错误

MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk

 意思是:Redis被配置为保存数据库快照,但它目前不能持久化到硬盘。用来修改集合数据的命令不能用。请查看Redis日志的详细错误信息。

去网上搜了一下这个问题,网上说原因是强制关闭Redis快照导致不能持久化。给出的解决方案是运行config set stop-writes-on-bgsave-error no 命令后,关闭配置项stop-writes-on-bgsave-error解决该问题。

root@ubuntu:/usr/local/redis/bin# ./redis-cli
127.0.0.1:6379> config set stop-writes-on-bgsave-error no

完成以上操作后,重新刷新网页~真的可以了,牛逼!!然后我就去睡觉了。

然而又过了两天,网站又崩了~问题和上面一样,于是又去网上找解决方案,在这篇文章中找到了解决方案(https://www.cnblogs.com/qq78292959/p/3994349.html

文章中说道将config set stop-writes-on-bgsave-error 设置为no仅仅是让redis忽略了这个异常,使得程序能够继续往下运行,但实际上数据还是会存储到硬盘失败。

查看redis的日志,会发现一行警告:

“WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.”(警告:过量使用内存设置为0!在低内存环境下,后台保存可能失败。为了修正这个问题,请在/etc/sysctl.conf 添加一项 'vm.overcommit_memory = 1' ,然后重启(或者运行命令'sysctl vm.overcommit_memory=1' )使其生效。)

意思是说我系统内存不足,我看了下系统内存 free -m,明明还有挺多内存的啊。

迷迷糊糊中我跟着修改vm.overcommit_memory=1后问题果然解决了。有个问题,那明明系统内存还够,为什么redis会认为redis内存不足呢。上面链接中的文章也给出了问题原因分析

redis认为内存不足原因:http://www.linuxidc.com/Linux/2012-07/66079.htm,简单地说:Redis在保存数据到硬盘时为了避免主进程假死,需要Fork一份主进程,然后在Fork进程内完成数据保存到硬盘的操作,如果主进程使用了4GB的内存,Fork子进程的时候需要额外的4GB,此时内存就不够了,Fork失败,进而数据保存硬盘也失败了。

而将vm.overcommit_memory改为1有什么作用呢,网上看到一个博客是如下解释,我个人也比较同意

0 — 默认设置。个人理解:当应用进程尝试申请内存时,内核会做一个检测。内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。举个例子,比如1G的机器,A进程已经使用了500M,当有另外进程尝试malloc 500M的内存时,内核就会进行check,发现超出剩余可用内存,就会提示失败。
1 — 对于内存的申请请求,内核不会做任何check,直到物理内存用完,触发OOM杀用户态进程。同样是上面的例子,1G的机器,A进程500M,B进程尝试malloc 500M,会成功,但是一旦kernel发现内存使用率接近1个G(内核有策略),就触发OOM,杀掉一些用户态的进程(有策略的杀)。
2 — 当 请求申请的内存 >= SWAP内存大小 + 物理内存 * N,则拒绝此次内存申请。解释下这个N:N是一个百分比,根据overcommit_ratio/100来确定,比如overcommit_ratio=50,那么N就是50%。
 

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐