某一天的中午,测试了MySQL关闭的一个小场景,简单分析一下。
01
背景
背景介绍:
线上某个MySQL实例需要关停,跟同事沟通了一下关停MySQL的方法。常见的关停MySQL实例的方法有:
1、利用mysqladmin工具关停;
2、如果是MySQL5.7及以上版本,利用shutdown命令关停,当然MySQL8.0版本还支持restart命令来重启
3、利用Linux的kill命令来kill MySQL对应的进程号关停
脚本里面更多的是使用mysqladmin工具,实际操作中,使用后面2种方法居多。
今天我们主要看下kill命令对MySQL的影响。
02
测试
MySQL启动的时候,一般来讲有一个调用关系,mysql.server调用mysqld_safe,mysqld_safe调用mysqld,其中:
1、mysql.server是mysql安装目录support_file下的一个文件,它调用了mysqld_safe;
2、mysqld_safe是一个守护进程,守护mysqld进程,在mysqld进程异常退出的时候,自动将mysqld进程拉起来;
3、mysqld是真正的mysql服务进程
一般我们通过service mysql.server start来启动MySQL进程,或者通过手工mysqld_safe命令行的办法来启动MySQL进程,启动完成的进程,通常如下:
[root@yeyz ~]# ps -ef|grep mysql root 22899 22820 00:00:00 grep --color=auto mysql root 30344 1 00:00:00 /bin/sh /usr/local/mysql-8.0.22/bin/mysqld_safe --defaults-file=/data1/mysql_4307/my.cnf mysql 31513 30344 00:09:32 /usr/local/mysql-8.0.22/bin/mysqld --defaults-file=/data1/mysql_4307/my.cnf --basedir=/usr/local/mysql-8.0.22 --datadir=/data1/mysql_4307/data --plugin-dir=/usr/local/mysql-8.0.22/lib/plugin --user=mysql --log-error=/data1/mysql_4307/log/mysql.err --open-files-limit=16384 --pid-file=/data1/mysql_4307/tmp/mysql.pid --socket=/data1/mysql_4307/tmp/mysql.sock --port=4307
可以看到:
有一个pid为30344的mysqld_safe进程;
有一个pid为31513的mysqld进程,mysqld进程的父进程是30344这个mysqld_safe进程
此时我们利用kill命令停止mysqld进程,怎么做???使用kill命令还是kill -9 命令???这俩命令有啥区别???我们一起看一下。
先来看kill命令
我们kill命令kill掉31513这个进程:
[root@yeyz ~]# kill 31513 [root@yeyz ~]# ps -ef|grep mysql root 22951 22820 0 23:19 pts/0 00:00:00 grep --color=auto mysql
可以看到,kill命令,kill掉了31513进程,mysqld进程不存在了,而mysqld_safe这个守护进程,没有将mysqld进程再度拉起。
再来看kill -9 命令
[root@yeyz ~]# ps -ef|grep mysql root 23051 22820 00:00:00 /bin/sh /usr/local/mysql-8.0.22/bin/mysqld_safe --defaults-file=/data1/mysql_4307/my.cnf mysql 24141 23051 00:00:00 /usr/local/mysql-8.0.22/bin/mysqld --defaults-file=/data1/mysql_4307/my.cnf --basedir=/usr/local/mysql-8.0.22 --datadir=/data1/mysql_4307/data --plugin-dir=/usr/local/mysql-8.0.22/lib/plugin --user=mysql --log-error=/data1/mysql_4307/log/mysql.err --open-files-limit=16384 --pid-file=/data1/mysql_4307/tmp/mysql.pid --socket=/data1/mysql_4307/tmp/mysql.sock --port=4307 # 手工kill [root@yeyz ~]# kill -9 24141 [root@yeyz ~]# /usr/local/mysql-8.0.22/bin/mysqld_safe: line 199: 24141 Killed 2022-03-28T15:20:25.159403Z mysqld_safe Number of processes running now: 0 2022-03-28T15:20:25.163726Z mysqld_safe mysqld restarted # 查看结果 [root@yeyz ~]# ps -ef|grep mysql root 23051 22820 00:00:00 /bin/sh /usr/local/mysql-8.0.22/bin/mysqld_safe --defaults-file=/data1/mysql_4307/my.cnf mysql 24232 23051 00:00:01 /usr/local/mysql-8.0.22/bin/mysqld --defaults-file=/data1/mysql_4307/my.cnf --basedir=/usr/local/mysql-8.0.22 --datadir=/data1/mysql_4307/data --plugin-dir=/usr/local/mysql-8.0.22/lib/plugin --user=mysql --log-error=/data1/mysql_4307/log/mysql.err --open-files-limit=16384 --pid-file=/data1/mysql_4307/tmp/mysql.pid --socket=/data1/mysql_4307/tmp/mysql.sock --port=4307
可以看到,kill -9命令,kill掉了24141进程,mysqld进程被kill掉了,但是mysqld-safe这个守护进程将mysqld再度拉起,新进程的pid是24232
03
总结
从这个测试中,可以得到如下规律:
1、使用kill命令,kill掉mysqld进程,mysqld_safe不会自动拉起mysqld进程;
2、使用kill -9 命令,kill掉mysqld进程,mysqld_safe会自动拉起mysqld进程
其实这说明,kill命令和kill -9命令的机制是不一样的,我们可以使用kill -l命令来查看kill命令的信号说明:
[root@yeyz ~]# kill -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
可以看到,kill的信号有64个。
我们使用kill -9 pid,也就是sigkill信号。
默认的kill命令,不带数字,相当于kill -15 pid,也就是sigterm信号。
当我们给一个进程发送sigterm信号的时候,进程受到这个信号之后,后续的工作是自己处理的,此时一般情况有三种:
1、继续执行程序,忽略kill信号;
2、进程释放掉相应的资源后关停进程;
3、立即停止进程
简单理解,就是进程自己决定使用哪一种方案来"优雅,安全的退出",一般进程都会进行资源回收,临时文件释放等工作,然后退出,如果这个过程中发生了阻塞,则进程会忽略kill操作,也就是我们经常遇到的“kill 不掉”的情况。
当我们给一个进程发送一个sigkill的信号的时候,这个信号要求进程立即停止,不允许出现阻塞或者被进程忽略的情况,一般进程来不及做"资源释放,临时文件回收"等工作,所以经常会带来一些副作用例如数据丢失等。这个方案要慎用。
从上面的描述,结合之前的知识储备,我们不难总结:
kill mysqld进程,本身是优雅、安全退出mysql的一种方法,所以mysqld_safe认为这个操作是被允许的;
相反,kill -9 mysqld进程,本身是一种粗暴退出mysql的方法,所以mysqld_safe认为这个操作是"意外的,计划外的",所以会帮我们拉起mysqld进程。
如果我们打开mysqld_safe文件,还可以看到如下的命令:
while true do xxxx if $dont_restart_mysqld; then if test ! -f "$pid_file" # This is removed if normal shutdown then break xxxx done
如果pid不存在(意味着正常关闭,删除了pid文件),则break,跳出这个监听循环。
如果pid存在(意味着非正常关闭,未删除pid文件),则继续监听mysqld进程