首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >[MYSQL] mysqld_safe进程离奇失踪的案例分享

[MYSQL] mysqld_safe进程离奇失踪的案例分享

原创
作者头像
大大刺猬
发布2025-07-01 16:17:36
发布2025-07-01 16:17:36
15900
代码可运行
举报
文章被收录于专栏:大大刺猬大大刺猬
运行总次数:0
代码可运行

导读

对于mysqld的启停我们可以使用mysqld_safe或者服务来管理, 本案例使用前者. 好处是:mysqld异常挂了之后,会被拉起来.

那么mysqld_safe挂了呢? 谁来拉它呀!

不巧的是, 本次案例就是mysqld_safe挂了.(本案例和mysql无法, 不方便模拟, 所以后续内容仅以文字描述, 并提供相关命令)

现象

前几天给某个mysql实例重启(释放内存)后, 发现mysqld_safe进程没了. mysql.err没有任何信息. /var/log/message也没得任何信息. 仿佛凭空消失了一样(被kill?).

这种通常有3种情况:

  1. OOM (mysqld_safe就一个脚本, 占不了多少内存,基本上可以排除), 使用dmesg -T 未发现任何信息.
  2. 人为的kill mysqld_safe进程, 查看历史记录,未发现相关命令(root账号启动的Mysqld_safe,普通账号也没得权限)
  3. 某些使用root启动的脚本给mysqld_safe kill了. 这种排查比较困难, 但前两种已经排除了, 就只有啃这块硬骨头了.

处理过程

迷雾重重

首先先看下除了这套环境外, 还有哪些环境的mysqld_safe也没了. 通过巡检记录发现, 还有几套系统的mysqld_safe进程也没了. 有的是半年前的, 有的是最近的. 但有个共同点就是: 使用自动化部署或者重启的.

测试环境使用自动化重启mysqld实例, 成功复现该问题(不到3分钟,mysqldsafe就挂了). ~~故: 这个锅得甩给自动化了(--)~~

但自动化也是调用的脚本来跑的啊.大概流程如下:

这个逻辑也没啥问题啊, 而且自动化切换之类的都使用得好好的. 难道不是自动化的原因, 是mysqld_safe的原因? 还是脚本调用层级太多了?

初见端倪

作为对照, 我们写个脚本来模拟这个多次调用过程. 遗憾的是mysqld_safe一直都活得好好的.(起码把锅给自动化扣牢了)

起码证明了mysqld_safe脚本是没得问题的. 那我们看下自动化的日志吧, 日志在哪? 不知道! 我们使用万能的grep -r, 找啥关键词,当然是mysqld_safe的pid啊.

代码语言:shell
复制
# 找到自动化相关的目录
ps -ef | grep xx 
# 通过pid找到相关的信息
grep -r 'MYSQLD_SAFE_PID' xxx

果然找到了 kill MYSQLD_SAFE_PID 之类的信息. 那么为啥要kill mysqld_safe进程呢?

拨云见日

我们根据对于的日志信息再使用grep -r KEY来找到对应的代码(这种自动化的, 很多都是py写的, 所以找起来还是比较简单的).

于是我们找到了如下类似逻辑(如下为伪代码):

代码语言:python
代码运行次数:0
运行
复制
for p in process_list:
	if p.cwd().startswith('XX_ROOT_DIR') and p.ppid == 1:
		p.kill()

看起来的逻辑就是判断 该进程的cwd(current working directory)是否和自动化的目录一致, 并且父进程是否为1, 是的话,直接kill. 用途估计是回收某些zombie进程.

XX_ROOT_DIR 表示某某软件的根目录. 这种设置主要是解决一些路径问题.

从逻辑来讲是没得啥大问题的. 但是我们的mysqld_safe为啥没了呢? 能匹配上这个逻辑? 通常我们启动的Mysqld_safe的cwd是mysql_base之类的, 不太可能是XX_ROOT_DIR之类的

恍然大悟

难道我们的Mysqld_safe的cwd路径变为了XX_ROOT_DIR ? 我们修改下 "脚本A", 在调用启动脚本之前, 显示下当前路径, 然后cd到其它目录,再执行启动脚本

代码语言:shell
复制
......
pwd
cd ${START_SCRIPT_DIR%/*}
pwd
${START_SCRIPT_DIR}
....

然后观察发现: 第一个路径确实是XX_ROOT_DIR, 并且由于使用了cd ${START_SCRIPT_DIR%/}命令, 我们mysqld_safe的cwd路径也确实变为了${START_SCRIPT_DIR%/}. 而且mysqld_safe进程一直都活得好好的!

所以就是自动化调用的时候把我们的cwd目录改了? 我们查看mysqld_safe脚本的时候, 发现如下信息:

代码语言:txt
复制
# mysql.server works by first doing a cd to the base directory and from there
# executing mysqld_safe

大意是mysqld_safe运行的时候会cd到mysql base目录. 那自动化的为啥还能给我们cd到其它目录去呢?

不对, 自动化是调用的mysqld_safe, 所以是mysqld_safe最后修改, 那应该优先生效才对, 除非没有设置basedir

代码语言:shell
复制
find_basedir_from_cmdline () {
  for arg in "$@"; do
    case $arg in
      --basedir=*)
        MY_BASEDIR_VERSION="`echo "$arg" | sed -e 's;^--[^=]*=;;'`"
        # Convert to full path
        cd "$MY_BASEDIR_VERSION"
        if [ $? -ne 0 ] ; then
          log_error "--basedir set to '$MY_BASEDIR_VERSION', however could not access directory"
          exit 1
        fi
        MY_BASEDIR_VERSION="`pwd`"
        ;;
    esac
  done
}
oldpwd="`pwd`"
find_basedir_from_cmdline "$@"

于是我们检查了启动mysqld_safe的脚本, 发现: 果然没有设置--basedir.

于是就使用了自动化软件的XX_ROOT_DIR目录,导致被误以为是自动化软件的目录给干掉了.

所以是谁的锅呢?

总结

原因: mysqld_safe被自动化当作自己的进程给kill了

本次锅不好甩.

本次案例看似是自动化的锅: 手动执行没得问题, 使用自动化执行就有问题, 那不就是自动化的锅么

但: cwd为自己目录也没有问题啊, 把cwd为自己目录的进程干掉以回收资源也没啥问题啊.

又但: 不是你的进程, 你干嘛要kill呢? 你完全可以在某个文件记录你自己进程的pid啊. 你这随便kill也太离谱了.

又又但: 你mysqld_safe不是都支持basedir之类的来指定cwd路径么, 你自己不用, 怪谁呢

又又又但: 有选项又没表示一定要使用, 本来就没必要使用啊, 在哪都不影响我使用啊.

.........

解决方法有2种:

  1. 修改启动脚本, 加个--basedir (修改数量太多)
  2. 自动化调用之前先 cd 到指定目录(推荐)

在kill进程这种操作的时候要稳一点, 尤其是数据库服务器; 如果本次是mysqld进程的话, 不就gg了么. 还是觉得自动kill进程比较离谱(虽然初衷是好的).

参考:

https://dev.mysql.com/doc/refman/8.0/en/mysqld-safe.html

https://www.kernel.org/doc/html/latest/filesystems/proc.html

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导读
  • 现象
  • 处理过程
    • 迷雾重重
    • 初见端倪
    • 拨云见日
    • 恍然大悟
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档