现象
之前碰到的一个问题。服务运行一段时间,莫名其妙挂掉,一开始以为是自己关闭了进程忘记了重启。查看日志发现最后一条日志的时间点,我并没有操作服务器。也就是说,服务是自己挂掉的。
问题排查
查看服务日志,没有任何异常。
查看/var/log/messages文件,发现其中有oom,这是被系统kill了。
Sep 18 00:08:45 vultr kernel: Out of memory: Kill process 9211 (java) score 443 or sacrifice child
Sep 18 00:08:45 vultr kernel: Killed process 9211 (java) total-vm:2185956kB, anon-rss:227232kB, file-rss:0kB, shmem-rss:0kB
手动启动服务,jps查看进程,根据进程id,top -p PID查看进程的内存占用情况,发现空闲情况下,内存占用有41%。free -h查看487M内存已使用384M,且swap为0,没有虚拟内存。
查询资料得知kernel中oom的机制:
VM里分配不出更多的page时,就会触发oom。此时VM会调用__out_of_memory()函数,该函数会先调用select_bad_process选择一个要kill的进程,再调用oom_kill_process杀死select出来的进程。
其中,select_bad_process函数扫描整个进程列表,为每个进程计算一个score,score最高的会被选中。
此时,真相已慢慢浮出水面。高度怀疑是服务压力增大,吃掉了内存,触发系统oom,所以被杀。
复现
接下来,尝试复现进程被杀的情况,以验证我的猜想。
使用Jmeter,频繁调用服务内的一个查询接口。持续了没一会,Jmeter中开始出现一连串的接口调用失败。关闭Jmeter,马上jps查看进程,果然,进程没了!
查看服务日志,还是没异常。查看/var/log/messages,出现了一个新的oom,时间吻合。
至此,问题复现。
可以得出结论:服务器内存不足导致进程被杀。
查询资料得知kernel中oom的机制:
VM里分配不出更多的page时,就会触发oom。此时VM会调用__out_of_memory()函数,该函数会先调用select_bad_process选择一个要kill的进程,再调用oom_kill_process杀死select出来的进程。
其中,select_bad_process函数扫描整个进程列表,为每个进程计算一个score,score最高的会被选中。
解决方案
方法一:
可以通过设置/proc/
方法二:
创建swap分区,利用虚拟内存缓解压力。
1.创建swap文件,if为空字符设备,读取/dev/zero可以提供无限的空字符(NULL, ASCII NUL, 0x00),创建文件时,使用该设备进行输入,占用指定大小的空间,of为swap文件路径,bs为块大小,count为块数量。
dd if=/dev/zero of=/var/swap bs=1M count=1024
2.设置swap分区。
mkswap /var/swap
3.开启swap分区。
swapon /var/swap
4.设置开机启动swap分区。
vim /etc/fstab
文件中加入
/var/swap swap swap defaults 0 0
5.查看内存情况,发现已有swap,完成。
free -h
此后,没有再出现过进程被杀的情况,问题解决~
其他命令
删除虚拟内存
1.去除/etc/fstab中新增的内容
2.关闭虚拟内存
// 关闭所有虚拟内存
swapoff -a
3.删除swap文件
rm -rf /var/swap