MySQL OOM 系统二 OOM Killer

这里就涉及到一个问题,到底Kill掉谁呢?一般稍微了解一些Linux内核的同学第一反应是谁用的最多,就Kill掉谁。这当然是Linux内核首先考虑的一种重要因素,但是也不完全是这样的,我们查一些Linux的内核方面的资料,可以知道其实Kill谁是由/proc/<pid>/oom_score来决定的,这个值每个进程一个,是由Linux内核的oom_badness()函数负责计算的。那下面我们来仔细读一读badness()函数。

在badness()函数的注释部分,写明了badness()函数的处理思路:

1) we lose the minimum amount of work done
         2) we recover a large amount of memory
         3) we don't kill anything innocent of eating tons of memory
         4) we want to kill the minimum amount of processes (one)
         5) we try to kill the process the user expects us to kill, this  algorithm has been meticulously tuned to meet the principle of least surprise ... (be careful when you change it)

总的来说就是Kill掉最小数量的进程来获取最大数量的内存,这与我们Kill掉占用内存最大的进程是吻合的。

/*
         * The memory size of the process is the basis for the badness.
         */

points = p->mm->total_vm;

分数的起始是进程实际使用的RAM内存,注意这里不包括SWAP,即OOM Killer只会与进程实际的物理内存有关,与Swap是没有关系的,并且我们可以看到,进程实际使用的物理内存越多,分数就越高,分数越高就越容易被牺牲掉。

/*
         * Processes which fork a lot of child processes are likely
         * a good choice. We add the vmsize of the childs if they
         * have an own mm. This prevents forking servers to flood the
         * machine with an endless amount of childs
         */
          ...
                  if (chld->mm != p->mm && chld->mm)
                        points += chld->mm->total_vm;

这段表示子进程占用的内存都会计算到父进程上。

s = int_sqrt(cpu_time);
        if (s)
                points /= s;
        s = int_sqrt(int_sqrt(run_time));
        if (s)
                points /= s;

这表明进程占用的CPU时间越长或者进程运行的时间越长,分数越低,越不容易被Kill掉。

/*
        * Niced processes are most likely less important, so double
        * their badness points.
        */
        if (task_nice(p) > 0)
                points *= 2;

如果进程优先级低(nice值,正值低优先级,负值高优先级),则Point翻倍。

/*
        * Superuser processes are usually more important, so we make it
        * less likely that we kill those.
        */
        if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_ADMIN) ||
                                p->uid == 0 || p->euid == 0)
                points /= 4;

super用户的进程优先级较低。

/*
         * We don't want to kill a process with direct hardware access.
         * Not only could that mess up the hardware, but usually users
         * tend to only have this flag set on applications they think
         * of as important.
         */
        if (cap_t(p->cap_effective) & CAP_TO_MASK(CAP_SYS_RAWIO))
                points /= 4;

直接可以访问原始设备的进程优先级较高。

/*
         * Adjust the score by oomkilladj.
         */
        if (p->oomkilladj) {
                if (p->oomkilladj > 0)
                        points <<= p->oomkilladj;
                else
                        points >>= -(p->oomkilladj);

}

每个进程有个oomkilladj 可以设置该进程被kill的优先级,这个参数看上去对Point影响还是比较大的,oomkilladj 最大+15,最小是-17,越大越容易被干掉,这个值由于是移位运算,所以影响还是比较大的。

下面我写个小程序实验一下:

 #define MEGABYTE 1024*1024*1024
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 int main(int argc, char *argv[])
{
void *myblock = NULL;
myblock = (void *) malloc(MEGABYTE);
printf("Currently allocating 1GB\n");
sleep(1);
int count = 0;
while( count < 10)
{
 memset(myblock,1,100*1024*1024);
 myblock = myblock + 100*1024*1024;
 count++;
 printf("Currently allocating %d00 MB\n",count);
 sleep(10);
  }
  exit(0);
 }

上面的程序先申请一个1G的内存空间,然后100M为单位,填充这些内存空间。在一个2G内存,400M Swap空间的机器上跑3个上面的进程。我们看一下运行结果:

test1、test2、test3分别申请了1G的虚拟内存空间(VIRT),然后每隔10s,实际占用的RAM空间就增长100M(RES)。

当物理内存空间不足时,OS开始进行Swap,可用的Swap空间开始减少。

当内存是在没有可分配的空间时,test1进程被操作系统Kill掉了。dmesg 我们可以看到,test1进程被OS Kill掉,同时oom_score为1000。

这3个进程的oom_adj全部都是默认值0。下面我们来实验一下设置了oom_adj的效果。重新启动3个进程,然后我们看到test2的PID是12640

我们运行一下下面的语句

echo 15 > /proc/12640/oom_adj

一段时间后,我们看到Swap空间急剧减少,基本上OS OOM_Killer要开动了。

果然,不出意料,12640进程被kill掉了。

所以为了避免自己需要的进程被kill掉,可以通过设置进程的oom_adj来实现。当然,有的人会说,这一切都是超售引起的,既然Linux提供了overcommit_memory可以禁用overcommit特性,那为什么不禁用呢。这有利也有弊,一旦禁用overcommit,就意味着MySQL根本无法申请超过实际内存的空间,而在MySQL中,存在很多动态申请内存空间的地方,如果申请不到,MySQL就会Crash,这大大增加了MySQL宕机的风险,这也是Linux为什么要overcommit的原因。

有了上面的分析,我们不难看出,如果在不设置oom_adj的前提下,MySQL一般都会成为OOM_Killer的首选对象,因为MySQL一般都是内存的最大占用者。那作为MySQL,我们如何尽量的去规避被Kill的风险呢,下一章我们将重点从MySQL的角度分析如何规避OOM。

时间: 2016-07-15

percona-toolkit之pt-kill 杀掉mysql查询或连接的方法

pt-kill 是一个非常简单的 杀mysql线程和查询的 工具. 主要是为了防止一些长的查询 长时间占用 系统资源,而对线上业务造成影响的情况. 主要作用: 从show processlist 中获取满足条件的连接或者从包含show processlist的文件中读取满足条件的连接并打印或者杀掉或者执行其他操作. 我们这里主要用来防止某些select操作时间过长,从而影响其他线上SQL. 安装: 安装percona-toolkit即可 使用范例: pt-kill --log-dsn D=tes

批量 kill mysql 中运行时间长的sql

 KILL语法 KILL [CONNECTION | QUERY] thread_id 每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. KILL允许自选的CONNECTION或QUERY修改符: · KILL CONNECTION与不含修改符的KILL一样:它会终止与给定的thread_id有关的连接. · KILL QUERY会终止连接当前正在执行的语句,但是会保持连接的

MySQL Slave 触发 oom-killer解决方法

最近经常有收到MySQL实例类似内存不足的报警信息,登陆到服务器上一看发现MySQL 吃掉了99%的内存,God ! 有时候没有及时处理,内核就会自己帮我们重启下MySQL,然后我们就可以看到 dmesg 信息有如下记录: Mar 9 11:29:16 xxxxxx kernel: mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0 Mar 9 11:29:16 xxxxxx kerne

Mysql使用kill命令解决死锁问题(杀死某条正在执行的sql语句)

在使用mysql运行某些语句时,会因数据量太大而导致死锁,没有反映.这个时候,就需要kill掉某个正在消耗资源的query语句即可, KILL命令的语法格式如下: KILL [CONNECTION | QUERY] thread_id 每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. KILL允许自选的CONNECTION或QUERY修改符:KILL CONNECTION与不

MySQL OOM 系列三 摆脱MySQL被Kill的厄运

前面两章,我们分析了Linux内存分配的策略以及Linux通过使用 OOM_Killer的机制解决了"超售"引起的风险,MySQL同其他的应用程序一样,在操作系统允许的范围内也是可以超售的,一般人理解,Innodb_buffer_pool必须小于实际物理内存,否则MySQL会启动失败.其实这是一个误区,这个不是MySQL层控制的,这个是操作系统(OS)层控制的,就是前面提到的/proc/sys/overcommit_memory控制OS是否允许"超售".如果允许&q

MySQL OOM 系列一 Linux内存分配

RDS(网易云关系数据库服务)上线已经有一段时间,陆续不断有产品迁入到了RDS中,在线上运维的过程中,也遇到了一些曾经没有考虑到,或者考虑的不全的东西.后续有时间可以分享给大家. 今天想提到的是线上一个4G的RDS实例,发生了OOM(out of memory)的问题,MySQL进程被直接Kill掉了.在解释这个问题的时候,我们首先需要从Linux系统内存分配策略讲起.     一般写C语言程序,我们习惯使用malloc动态的申请内存空间(Java由JVM负责内存管理),malloc函数会向操作

Mysql精粹系列(精粹)

关于Mysql整理的需要记忆和熟练掌握的内容 1. /* 查看操作 */ ------------------------------------------------------------------------------------------------------- 1. /* 查看操作 */ SHOW PROCESSLIST -- 显示哪些线程正在运行 SHOW VARIABLES -- 查看变量 2. /* 数据库操作 */ --------------------------

sqlserver、Mysql、Oracle三种数据库的优缺点总结

一.sqlserver优点:易用性.适合分布式组织的可伸缩性.用于决策支持的数据仓库功能.与许多其他服务器软件紧密关联的集成性.良好的性价比等:为数据管理与分析带来了灵活性,允许单位在快速变化的环境中从容响应,从而获得竞争优势.从数据管理和分析角度看,将原始数据转化为商业智能和充分利用Web带来的机会非常重要.作为一个完备的数据库和数据分析包,SQLServer为快速开发新一代企业级商业应用程序.为企业赢得核心竞争优势打开了胜利之门.作为重要的基准测试可伸缩性和速度奖的记录保持者,SQLServ

安装MySQL常见的三种方式

目录 安装MySQL的方式常见的有三种: rpm包形式 通用二进制形式 源码编译 1,rpm包形式 (1) 操作系统发行商提供的 (2) MySQL官方提供的(版本更新,修复了更多常见BUG)www.mysql.com/downloads 关于MySQL中rpm包类型的介绍: MySQL-client         客户端组件  MySQL-debuginfo      调试MySQL的组件  MySQL-devel          想针对于MySQL编译安装PHP等依赖于MySQL的组件包

SpringBoot入门系列之JPA mysql

一,准备工作,建立spring-boot-sample-mysql工程 1.http://start.spring.io/ A.Artifact中输入spring-boot-sample-MySQL      B.勾选Web下的web      C.勾选SQL下的JPA MYSQL 2.Eclips中导入工程spring-boot-sample-mysql A.解压快捷工程spring-boot-sample-mysql到某文件夹 B.eclips中file->import->Import E

Oracle、MySQL和SqlServe三种数据库分页查询语句的区别介绍

先来定义分页语句将要用到的几个参数: int currentPage ; //当前页 int pageRecord ; //每页显示记录数 以之前的ADDRESSBOOK数据表为例(每页显示10条记录): 一.SqlServe下载 分页语句 String sql = "select top "+pageRecord +" * from addressbook where id not in (select top "+(currentPage-)*pageRecor

详解Ubuntu Server下启动/停止/重启MySQL数据库的三种方式

Ubuntu Server下启动/停止/重启MySQL数据库的三种方式 系统环境:ubuntu server 12.10 x64(mysql为系统自带) 当我们需要修​​改MySQL的配置文件my.cnf(windows 下为 my.ini)来进行一些设置的时候,修改完之后我们需要重启MySQL. my.cnf文件位置为:/ect/mysql/my.cnf Waring:如果该文件配置错误,MySQL将无法启动. 下面介绍三种方式对MySQL进行启动/停止/重启操作: 启动mysql: 方式一:

PHP程序员玩转Linux系列 备份还原MySQL

PHP程序员玩转Linux系列文章: 1.PHP程序员玩转Linux系列-怎么安装使用CentOS 2.PHP程序员玩转Linux系列-lnmp环境的搭建 3.PHP程序员玩转Linux系列-搭建FTP代码开发环境 前几天有个新闻,说是gitlab的工程师把数据文件给误删了,搞了个大事件,很多人都去围观了.备份工作应该在最开始的时候就要做,否则就会失去最佳时机,为了保证我的数据是安全的,因此我要搞备份了.备份分为逻辑备份和物理备份,逻辑备份是导sql,物理备份是基于文件的,这两种我都搞一下. 开

mysql备份的三种方式详解

一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内完: 恢复的时候是否需要持续提供服务:恢复的对象,是整个库,多个表,还是单个库,单个表. 三.备份的类型 1.根据是否需要数据库离线 冷备(cold backup):需要关mysql服务,读写请求均不允许状态下进行:温备(warm backup): 服务在线,但仅支持读请求,不允许写请求:热备(ho