先说下项目背景 我们是在研发的DMZ环境上部署了我们的多个服务和中间件,为了节省资源,使用的docker部署在同一台物理机上,一个Postgres的服务运行着多个微服务的数据库实例,从某天开始,开发发现在web页面频繁报错,日志如下:
看日志像是数据库的IO报错,随后我通过:
iostat -x 1 100
命令查看了IO的使用率,发现当时IO率接近100%,随后立刻查看数据库日志,发现platform的数据库实例一直在执行查询操作,大约为每秒100次的频率,此时意识到问题可能是某一个实例的IO过于频繁,导致另一个APP的数据库查询报错,于是乎排查了相关的SQL,发现是由于两个业务场景使用了同一个消息队列的Topic,这就导致了我发了一条消息到topic1后,我消费这条消息,消费的逻辑里面又会继续发消息,进入一个死循环,解决方法比较简单,将topic名称修改为不同的就可以了,修改完之后查看IO使用率,稳定下来了,本以为此时修改完了问题,但是随后不久,开发表示再次复现问题,但是频次稍有降低。
再次执行iostat命令并且频繁发送请求,发现多次之后确实发生了之前的IO的报错,奇怪的是iostat的命令显示IO使用率无变化。
于是乎,再次翻阅日志发现在IO报错的上方出现了如下日志:
通过名称可以翻译为: 数据库系统处于恢复模式中
一脸懵逼,google了下这个错误,大概的意思是pg在重启的过程中需要重新加载和初始化磁盘文件,如果此时有请求过来便会回复:数据库系统处于恢复模式中
问题是数据库好好的使用中,没有人手动重启,所以会不会是自动重启,再次查看pg的日志:
发现在同样的时间: 17:22:54的样子,数据库服务收到了一条killed的命令,随后数据库服务又被重新拉起,并进入恢复模式中,和开发确认下那个时间段没人操作数据库服务,那么可能是OS侧因为某些原因杀死了pg进程,于是乎,翻阅系统日志:/var/log/messages
同样的在: 17:22:54的时候,kernel发送了一条killed命令,原因是oom-killer,内存溢出,并且打印了如下日志:
memory: usage 102400kB, limit 102400kB, failcnt 3618
使用内存100m,总内存限制100m,总内存限制100m的原因是docker启动的时候指定了-m 参数,也就是说由于数据库实例的增加,导致原有的数据库实例的100m内存不够用了,才发生了OOM的错误,导致数据库频繁重启并进入恢复模式中
至此:问题基本算被定为出来了,但是还有一个小疑问,在此环境的数据库出现问题后,我们把所有的数据库实例迁移到了另一个数据库服务,而docker启动命令没变,也就是说依然是100m内存,但是并没有发生错误,这又是为什么?
继续google查询,发现有如下三个系统参数可能会影响:
###是否允许内存过度分配###它是 内存分配策略可选值:0、1、2。###0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。###1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。###2, 表示内核允许分配超过所有物理内存和交换空间总和的内存vm.overcommit_memory### 内存过度分配的比例vm.overcommit_ratio### 使用swap分区做内存### 默认值swappiness=60,表示内存使用率超过100-60=40%时开始使用swap分区vm.swappiness
而在数据库正常的环境中:
vm.overcommit_memory = 0vm.overcommit_ratio = 50vm.swappiness = 10[root@localhost ~]# free -mtotalusedfreesharedbuff/cache availableMem:32010 11455 233 210 20321 19824Swap: 1023980 10159
异常的环境中:
vm.overcommit_memory = 0vm.overcommit_ratio = 50vm.swappiness = 60[root@mqtt ~]# free -mtotalusedfreesharedbuff/cache availableMem:31628 12498 2671473 18862 17259Swap: 0 0 0
对比差异:
发现异常的环境中根本就没有swap分区,那么内存在使用完毕之后就会调用oom_killer;
而正常的环境中的swap分区使用大小为80M, 通过docker stats命令查看发现
docker stats postgresCONTAINER IDNAMECPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDSe6f0729869fcpostgres0.14% 85.48MiB / 100MiB 85.48%633MB / 626MB 0B / 0B 44
内存使用大约85%左右,符合vm.swappiness = 10的设置。此时开始使用交换区,所以并不会发生OOM的异常。
至此问题基本解决。