前几天我的小小的WordPress服务器被攻击了,被五六台机器从不同的IP发起xmlrpc攻击,大约每秒80次请求的样子,虽然不算猛烈,但我的虚拟机本身太小了,单CPU仅1GB内存,于是频频出现内存紧张的情况,oom-killer会自动选择合适的进程牺牲掉,但它怎么就那么不开眼,每次都选中了最重要的mysqld进程。解决的思路很简单,就是减小mysqld进程的oom_score_adj值,因为oom-killer通过比较每个进程的oom_score来挑选要出局的进程,数值越大就越容易被选中,而手工调整oom_score是通过oom_score_adj来实现的,命令如下:

$ echo "-100" > /proc/<pid>/oom_score_adj

但是每次reboot或者mysql重启都需要重新设置一遍实在麻烦,怎样才能实现自动化呢?我的做法如下,虽然道理很简单,但实现过程中有好几个坑,包含了几个有用的知识点,所以有点共享价值。

要点一:如何修改systemd的服务脚本

首先,我想在启动mysql服务的时候就自动把 oom_score_adj 调整好,理论上应该通过修改启动脚本完成,问题是我用了CentOS 7,systemd的启动脚本与以前有很大的不同。还是让我们先找到它吧:

# systemctl status mariadb

● mariadb.service - MariaDB database server

Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)

显然/usr/lib/systemd/system/mariadb.service就是我们感兴趣的,可以直接修改,但不建议这么做,因为将来升级mariadb有可能会覆盖掉你的改动。更好的方式是这样的:创建一个新目录 “/etc/systemd/system/mariadb.service.d/”,把需要改动的内容放在该目录下的”.conf”文件里,文件名可以随便,但必须以”.conf”结尾。这个文件起的作用是对systemd的service文件做出补充,systemd的service文件包括三个主要部分:[Unit], [Service]和[Install],其中[Service]段定义了服务启停的方法,[Service]段中以下三个字段是最常用的:
ExecStart 用于定义启动服务的命令,
ExecStartPre 是启动服务之前执行的命令,
ExecStartPost 是启动服务之后执行的命令。
我们修改oom_score_adj的任务应该放在ExecStartPost部分,需要注意的是:命令必须使用全路径,因为systemd不提供设置好的PATH环境变量。(注:更多关于systemd的细节可参考Red Hat的系统管理指南)

$ mkdir /etc/systemd/system/mariadb.service.d

$ cd /etc/systemd/system/mariadb.service.d

$

$ cat > avoid_oom.conf

# avoid oom-killer

[Service]

ExecStartPost=/bin/sudo /usr/local/bin/oom_mysql.sh

我们只增加了一行有实质内容,即让mariadb.service在启动之后调用自定义的脚本oom_mysql.sh,我们在这个脚本中调整mysqld进程的oom_score_adj值,脚本如下 (因为mariadb会把mysqld的PID记录在/var/run/mariadb/mariadb.pid之中,所以在脚本中我们寻找mysqld进程号便简单了):

$ cat /usr/local/bin/oom_mysql.sh

#!/bin/bash

MYSQL_PIDFILE="/var/run/mariadb/mariadb.pid"

pgrep mysql > /dev/null

if [ ! $? ]; then

exit 1

fi

if [ -f "$MYSQL_PIDFILE" ]; then

MYSQL_PID=`cat $MYSQL_PIDFILE`

echo "-100" > /proc/$MYSQL_PID/oom_score_adj

else

exit 1

fi

exit 0

要点二:如何设置不用输入密码而且没有tty的sudo

为什么我要通过sudo来执行以上脚本呢?
ExecStartPost=/bin/sudo   /usr/local/bin/oom_mysql.sh
为什么不象下面这样直接执行呢?
ExecStartPost=/usr/local/bin/oom_mysql.sh

这是因为mariadb.service是以mysql用户的身份启动的,mysql用户不具备写入/proc的权限,而在oom_mysql.sh脚本中我们需要写入 /proc/<pid>oom_score_adj

mysql:x:27:27:MariaDB Server:/var/lib/mysql:/sbin/nologin

为了使mysql用户能够写入/proc/<pid>/oom_score_adj,我们利用了sudo。修改sudo配置的命令是visudo,如果不加 -f 参数,它默认修改配置文件/etc/sudoers,但直接改动/etc/sudoers不太稳妥,万一改坏了什么地方就有麻烦,所以推荐的方法是:把你要增加的sudoers配置放在/etc/sudoers.d/ 目录下的文件中,文件名可以随意。

$ visudo -f /etc/sudoers.d/4mysql

Defaults:mysql !requiretty

mysql  ALL=(ALL)       NOPASSWD: /usr/local/bin/oom_mysql.sh

我们把要增加的配置放进了4mysql文件里,内容只有两行,需要解释一下:因为mysql用户很特别,它是不能登录的,因为它的shell是/sbin/nologin,而且在自动启动mariadb.service的时候显然也不能依赖人工输入口令去执行sudo,所以它的sudoers配置需要一种特殊的权限–即无需输入口令就可以执行sudo命令,这就是上述第二行 “mysql ALL=(ALL) NOPASSWD:” 的意思;第一行表示mysql用户执行sudo可以无需tty(终端),因为RHEL和CentOS默认情况下sudo需要tty才能执行,否则会发生下列错误:

sudo: sorry, you must have a tty to run sudo

至此,我们的工作就完成了,最后重启mariadb.service即可:

$ systemctl daemon-reload

$ systemctl restart mariadb

再检查mysqld,发现它的oom_score_adj已经设置为-100了,正是我们所期望的:

$ cat /proc/10839/oom_score_adj

-100

怎样避免MYSQLD被OOM-KILLER杀死?相关推荐

  1. linux内核killler,Linux 的 OOM Killer 机制分析

    按需分配物理页面 很多情况下,一个进程会申请一块很大的内存,但只是用到其中的一小部分.为了避免内存的浪费,在分配页面时,Linux 采用的是按需分配物理页面的方式.譬如说,某个进程调用malloc() ...

  2. ubuntu虚拟机进程被杀死_Linux进程被杀掉(OOM killer),查看系统日志

    基本概念: Linux 内核有个机制叫OOM killer(Out Of Memory killer),该机制会监控那些占用内存过大,尤其是瞬间占用内存很快的进程,然后防止内存耗尽而自动把该进程杀掉. ...

  3. Linux OOM 自动杀死进程(转)

    Linux OOM 自动杀死进程 问题描述: 今天上班后,登录一台内网测试服务器,发现部分进程失踪 (Nginx/PHP-FPM/MySQL/Crond). 解决方法: 1.首先启动这些进程,保证正常 ...

  4. linux oom日志分析,oom killer理解和日志分析:知识储备

    oom killer日志分析,这是前篇,准备一些基础知识 带着问题看: 1.什么是oom killer 他是Linux内核设计的一种机制,在内存不足的会后,选择一个占用内存较大的进程并kill掉这个进 ...

  5. 理解和配置 Linux 下的 OOM Killer

    原文:http://www.vpsee.com/2013/10/how-to-configure-the-linux-oom-killer/ 最近有位 VPS 客户抱怨 MySQL 无缘无故挂掉,还有 ...

  6. (转载)Linux Out-of-Memory(OOM) Killer

    Linux有一个特性:OOM Killer,一个保护机制,用于避免在内存不足的时候不至于出现严重问题,把一些无关的进程优先杀掉,即在内存严重不足时,系统为了继续运转,内核会挑选一个进程,将其杀掉,以释 ...

  7. linux内核killler,Linux内核参数overcommit_memory和OOM killer介绍

    什么是Linux Overcommit和OOM overcommit_memory是一个内核对内存分配的一种策略,它有三个可选值:0.1.2. 0. 表示内核将检查是否有足够的可用内存供应用进程使用: ...

  8. linux内核中内存耗尽OOM killer

    当内存严重不足时,页分配器在多次尝试直接回收失败后,就会调用内存耗尽OOM killer,选择杀死进程,释放内存. 先看一段oom 输出的错误 [ 7981.765805] kthreadd invo ...

  9. oom killer

    首先了解一下什么是oom killer? 简单理解是, Linux内核里出于保护其他资源,不致于让系统立刻崩溃,采取了一种保护进程手段,当linux系统所剩的内存空间不足以满足系统正常运行时,把使用内 ...

  10. Linux内存清道夫--OOM Killer

    1.OOM Killer 1.1.OOM Killer定义 OOM(Out Of Memory) Killer作为linux系统中守护进程,主要在系统内存严重不足时开始工作.出现这种情况是因为服务器上 ...

最新文章

  1. java逻辑符号怎么打_Java的逻辑运算符?
  2. python 参数
  3. java开发app启动跳转到一个广告,Android实现点击通知栏后,先启动应用再打开目标Activity...
  4. Ceph 存储集群7-故障排除
  5. android 单元测试 多线程,单元测试多线程Android RxJava
  6. 《机器人学导论--Join J.Craig》第一章 绪论
  7. 排序sort,统计wc
  8. 逆序链表--递归思路
  9. 资产管理软件 GLPI的安装(转)
  10. 【Verilog HDL】2. 4选1数据选择器
  11. mysql 定义取值范围_MySQL中各种字段的取值范围
  12. 如何判断你是合格的高级iOS开发工程师?
  13. SASE 的核心能力:安全Web网关
  14. PayPal提现被退回的解决办法?(教程和费用)
  15. 小技巧---查看电脑型号
  16. Airtest+Poco+Pytest框架搭建1
  17. VUE父子组件-传数据的理解
  18. 拓嘉辰丰:拼多多赠品链接是怎样做出来的
  19. Drony 定向抓指定app的http,https包
  20. 工程项目部质量管理体系的控制要点分析

热门文章

  1. 技术分享连载(二十七)
  2. 信息传递(NOIP2015提高组Day1T2)
  3. 在PHP代码中处理JSON 格式的字符串的两种方法:
  4. 【J2SE】java实现简单照片查看器
  5. MySQL prepare语句的SQL语法
  6. 浪潮服务器 NF 8460M4 的PM8060 RAID卡设置添加热备方法
  7. oc73--NSArray使用
  8. 支援日本/厄瓜多尔震区 Skype推免费通话
  9. LNMP安装了哪些软件?安装目录在哪?
  10. gitlab详细安装过程,错误解决方案