记一次由Launchctl引发的Bug事件
记一次由 Launchctl 引发的Bug事件
起因
事情的起因是,on beach 的时候打开了自twuc以来都没有再动过的本地环境
发现Mysql密码忘了,于是想先关闭当前Mysql进程,然后再通过skip-grant-tables 跳过密码实现登录。
于是熟练的开始了terminal操作
突然发现,不对啊,为什么这个进程好像kill不掉呀
见鬼了。。。。。
作为一个唯物主义者,冷静片刻后,开始寻找解决思路。
从上面可以很明显看出,kill掉了9884 和 9971 这两个进程后,他两立马变成了新的进程号 10044 和 10131
首先,kill进程后其PID变更了,说明该进程不是关不掉的,而是在关掉之后,立马又被重新启动了,于是被分配了新的PID
那么,是谁重启了他们呢?
经过一番搜索后,终于在一篇讨论帖下面发现了一个线索:Unable to stop MySQL on OS X 10.10
里面高赞的答案里提到了launchctl
那么 launchctl 是什么呢?
launchctl
wiki上定义的 launchctl
a unified, open-source service management framework for starting, stopping and managing daemons, applications, processes, and scripts. Written and designed by Dave Zarzycki at Apple, it was introduced with Mac OS X Tiger and is licensed under the Apache License.
简而言之就是
launchctl用来启动、停止、管理daemons, applications, processes, scripts的软件,并且是由苹果公司推出的。
这里唯一能和上面我们描述的情况搭边的可能就是daemons了
那么daemons又是什么呢?
守护进程(Daemon)
继续上wiki定义:
In multitasking computer operating systems, a daemon (/ˈdiːmən/ or /ˈdeɪmən/)[1] is a computer program that runs as a background process, rather than being under the direct control of an interactive user. Traditionally, the process names of a daemon end with the letter d, for clarification that the process is in fact a daemon, and for differentiation between a daemon and a normal computer program. For example, syslogd is a daemon that implements system logging facility, and sshd is a daemon that serves incoming SSH connections.
Systems often start daemons at boot time that will respond to network requests, hardware activity, or other programs by performing some task. Daemons such as cron may also perform defined tasks at scheduled times.
总结一下,守护进程有这么几个特点
- 守护进程是后台进程,并不能被用户直接操作和控制
- 通常区别守护进程的方法是看进程名字是否是以d结尾
- 系统通常在开机的时候就会启动守护进程
问题的解决思路分析
在了解完上面两个东西后,我们逐渐明白了这两个的关系,即 在我的mac电脑上一定有一个用来启动Mysql的守护线程,并且很有可能是通过launchctl来进行管理的。
有了思路后,问题就简单了。
使用,launchctl list 我们可以看到当前被launchctl管理的所有服务的PID、status、label
通过launchctl list | grep mysql过滤后可以清楚地看到原来是这么个小东西在守护Mysql呀
此时,心急的小伙伴可能会直接 kill 43062 来结束这一切,然后你就会发现。。。
launchctl 启动的服务竟然无法通过kill 来关闭,甚至是强如 kill -9 也只是短暂的关闭后他又会重新“复活”(不过此时守护进程的状态变成了1,属于异常)(这里大胆猜测可能还有一个针对launchctl的守护进程,欢迎各位读者自行考证)
好了,不卖关子了,这里其实有更加优雅的方式来关闭。
通过查询文档可知,launchctl list中展示的服务,都是通过launchctl对 .plist 结尾的文件进行加载而产生的
而这些 .plist 一般存在于这五个文件夹中:
- /Library/LaunchDaemons/ # 由管理员定义的守护进程任务项
- /Library/LaunchAgents/ # 由管理员为用户定义的任务项
- ~/Library/LaunchAgents/ # 由用户自己定义的任务项
- /System/Library/LaunchAgents # 由当前登录用户定义的守护进程任务项
- /System/Library/LaunchDaemons # 和2差不多
我们的Mysql的任务项就在第三个中,并通过如下命令添加:
1 | launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mysql@5.7.plist # 设置开机启动并立即生效(-w)该服务 |
同理,当我们想关掉它的时候:
1 | launchctl unload -w ~/Library/LaunchAgents/homebrew.mxcl.mysql@5.7.plist # 设置开机关闭并立即生效(-w)该服务 |
最终效果:
可见,该服务成功关掉,同时Mysql service也关掉了
之后就可以愉快的通过mysql.server start 和 mysql.server stop 来愉快的手动开关Mysql服务啦(划掉,还是自动的省事一些,hh)
后记
后来我仔细想了想homebrew.mxcl.mysql@5.7.plist这个文件是哪来的,突然想到,twuc的时候on boarding的时候安装过一个homebrew
而通过homebrew 安装 docker 拉取Mysql 镜像时 使用过
1 | brew services start mysql |
该命令同时会在~/Library/LaunchAgents添加homebrew.mxcl.mysql@5.7.plist(从Mysql文件夹中复制过来),设置Mysql的开机启动
参考链接
一、全文版权归本作者所有,其他人不得用于商业活动
二、如需转载文章,务必全篇转载,不得进行未经本人同意的修改
三、如需转载文章,必须注明出处和作者,以方便其他读者溯源。



