前言
前一段时间,业务部门的系统不定时的反馈,系统打开不了,提示:
等技术开发同学反应过来去查看业务状态时,服务又恢复了,由于不是核心的业务,并且出问题差不多1分钟左右,没太在意,但过一会或过一天一定时的又有反馈过来了,开始重视这个问题,总的来説这个问题的表现是,连不上mysql数据库,并且在1分钟左右会自恢复,首先让我们负责运维的同学去看看mysql的日志,这一看,果然发现了问题:
# Query_time: 52.047320 Lock_time: 0.000000 Rows_sent: 0 Rows_examined: 0
SET timestamp=1670245901;
SET character_set_connection=gbk, character_set_results=gbk, character_set_client=binary;
/usr/local/Kaiyuan/mysql/bin/mysqld, Version: 5.7.20-log (MySQL Community Server (GPL)). started with:
Tcp port: 3306 Unix socket: /tmp/mysql.sock
Time Id Command Argument
mysql服务会不定时的自动重启,经过分析,我的运维的同学确定系统
OOM
了
什么是OOM,OOM时为什么会自动重启mysql服务,后来经过优化mysql配置文件的参数减少mysql进程对内存的占用,OOM情况再也没发生过了
下面我们一起来了解一下OOM的真面目吧!
提示:OOM 英文全拼是 Out-Of-Memory
一、OOM是什么?
OOM:out of memory,字面意思当然是系统内存溢出。
Linux 内核有个机制叫OOM killer(Out-Of-Memory killer),该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽而内核会把该进程杀掉。
oom_killer是Linux自我保护的方式,内核检测到系统内存不足、挑选并杀掉某个进程的过程可以参考内核源代码linux/mm/oom_kill.c,当系统内存不足的时候,out_of_memory()被触发,然后调用select_bad_process()选择一个”bad”进程杀掉。如何判断和选择一个”bad进程呢?linux选择”bad”进程是通过调用oom_badness(),挑选的算法和想法都很简单很朴实:最bad的那个进程就是那个最占用内存的进程
很不幸的我们的mysql服务占用的内存最大,内核就把他干掉了。出现了短暂的连不上数据库的情况
二、Centos如何查看OOM日志
1.方法一
命令行如下:
grep "Out of memory" /var/log/messages
执行结果:
系统已经悄悄的杀掉很多次mysql服务,确实需要优化了
2.方法二
命令行如下:
dmesg -T | grep -i 'memory'
执行结果如下:
Nov 27 17:00:15 ecs-2c95-0002 kernel: Out of memory: Kill process 64254 (mysqld) score 695 or sacrifice child
Nov 28 14:09:27 ecs-2c95-0002 kernel: Out of memory: Kill process 3215 (mysqld) score 659 or sacrifice child
Nov 29 10:33:08 ecs-2c95-0002 kernel: Out of memory: Kill process 15119 (mysqld) score 669 or sacrifice child
Nov 29 21:48:36 ecs-2c95-0002 kernel: Out of memory: Kill process 19707 (mysqld) score 675 or sacrifice child
Nov 30 18:28:44 ecs-2c95-0002 kernel: Out of memory: Kill process 63421 (mysqld) score 662 or sacrifice child
Dec 1 12:58:29 ecs-2c95-0002 kernel: Out of memory: Kill process 19816 (mysqld) score 669 or sacrifice child
Dec 2 14:42:12 ecs-2c95-0002 kernel: Out of memory: Kill process 2989 (mysqld) score 680 or sacrifice child
Dec 3 03:32:40 ecs-2c95-0002 kernel: Out of memory: Kill process 45074 (mysqld) score 669 or sacrifice child
Dec 3 03:32:40 ecs-2c95-0002 kernel: Out of memory: Kill process 35468 (mysqld) score 669 or sacrifice child
Dec 4 14:53:02 ecs-2c95-0002 kernel: Out of memory: Kill process 35663 (mysqld) score 681 or sacrifice child
Dec 5 10:44:49 ecs-2c95-0002 kernel: Out of memory: Kill process 48800 (mysqld) score 660 or sacrifice child
Dec 5 21:12:42 ecs-2c95-0002 kernel: Out of memory: Kill process 65492 (mysqld) score 670 or sacrifice child
Dec 6 18:23:23 ecs-2c95-0002 kernel: Out of memory: Kill process 43404 (mysqld) score 677 or sacrifice child
Dec 7 11:05:08 ecs-2c95-0002 kernel: Out of memory: Kill process 18159 (mysqld) score 662 or sacrifice child
Dec 8 08:38:02 ecs-2c95-0002 kernel: Out of memory: Kill process 44705 (mysqld) score 741 or sacrifice child
Dec 9 07:58:38 ecs-2c95-0002 kernel: Out of memory: Kill process 24619 (mysqld) score 736 or sacrifice child
三、OOM时,依据什么杀掉进程?
参数:panic_on_oom: 用来控制当内存不足时是否启用OOM
值为0:内存不足时,启动 OOM killer。
值为1:内存不足时,有可能会触发 kernel panic(系统重启),也有可能启动 OOM killer。
值为2:内存不足时,表示强制触发 kernel panic,内核崩溃GG(系统重启)。
参数:oom_kill_allocating_task: 用来决定杀掉哪种进程
值为0:会 kill 掉得分最高的进程。
值为非0:会kill 掉当前申请内存而触发OOM的进程。
当然,一些系统进程(如init)或者被用户设置了oom_score_adj的进程等可不是说杀就杀的。
参数:oom_dump_tasks:用来记录日志
oom_dump_tasks参数可以记录进程标识信息、该进程使用的虚拟内存总量、物理内存、进程的页表信息等。
值为0:关闭打印上述日志。在大型系统中,可能存在上千进程,逐一打印使用内存信息可能会造成性能问题。
值为非0:有三种情况会打印进程内存使用情况。
1、由 OOM 导致 kernel panic 时;
2、没有找到符合条件的进程 kill 时;
3、找到符合条件的进程并 kill 时。
参数:oom_adj、oom_score_adj 和 oom_score:用来控制进程打分(分数越高,就先杀谁)
这三个参数的关联性比较紧密,都和具体的进程相关,位置都是在 /proc/进程PID/ 目录下。
内核会对进程打分(oom_score),主要包括两部分,系统打分和用户打分。系统打分就是根据进程的物理内存消耗量;用户打分就是 oom_score_adj 的值。如果用户指定 oom_score_adj 的值为 -1000,也就是表示禁止 OOM killer 杀死该进程。
用户可以通过调整 oom_score_adj 的值来决定最终 oom_score 的值,oom_score_adj 的取值范围是 -1000~1000,为0时表示用户不调整 oom_score。另外,root进程拥有3%的内存使用特权,因此做最终 oom_score 计算时需要减去这些内存使用量。
oom_adj是一个旧的接口参数,其功能类似oom_score_adj,为了兼容,目前仍然保留这个参数,当操作这个参数的时候,kernel实际上是会换算成oom_score_adj
四、本次的优化方法
本次问题产生的原因是mysql占用内存太大,产生了OOM,优化mysql配置文件 my.cnf的innodb_buffer_pool_size参数可以很好的解决
innodb_buffer_pool_size = 4G
总结
OOM是linux系统很重要的一项机制,是用来保护linux系统本身的,一旦出来OOM情况,我们应该从业务代码和服务的配置参数上着手优化,如果服务器配置太低,也以考虑增加物理内存来解决问题。