Kill 命令
一、 kill 命令的执行过程
-
大多数情况下有效: 例如长时间查询或锁等待。
-
收到 kill 后线程的操作:
-
设置线程状态为 THD::KILL_QUERY (或 THD::KILL_CONNECTION)。
-
给执行线程发送信号,唤醒处于等待状态的线程。
-
-
为什么不能立即停止?
-
线程可能持有锁等资源,直接终止会导致资源泄露。
-
kill 命令类似 Linux 的信号,是通知进程/线程可以开始终止逻辑。
-
-
终止过程的隐含逻辑:
-
语句执行过程中有“埋点”,判断线程状态是否为 THD::KILL_QUERY。
-
处于等待状态时,必须是可以被唤醒的等待(如锁等待使用 pthread_cond_timedwait)。
-
从进入终止逻辑到完成需要一个过程。
-
二、 kill 不掉的情况
第一类:线程未执行到判断线程状态的逻辑。
-
原因: 线程被阻塞在无法被信号唤醒的等待中,或者在等待过程中没有判断状态。
-
例子: innodb_thread_concurrency 不够用时,线程在等待进入 InnoDB 执行,循环调用 nanosleep,没有判断 KILL_QUERY 状态。
-
kill connection 的效果:
-
设置线程状态为 KILL_CONNECTION。
-
关闭网络连接(客户端收到断开提示)。
-
show processlist 显示 Command 为 Killed(因为状态是 KILL_CONNECTION)。
-
线程仍在等待中,直到满足条件进入 InnoDB 执行,才判断到状态进入终止逻辑。
-
-
其他类似情况: IO 压力过大导致读写函数无法返回。
第二类:终止逻辑耗时较长。
-
表现: show processlist 显示 Command 为 Killed,但线程未立即退出。
-
常见场景:
-
超大事务被 kill: 回滚操作需要回收所有新数据版本,耗时长。
-
大查询回滚: 生成临时文件较大,删除临时文件受 IO 影响。
-
DDL 最后阶段被 kill: 删除中间临时文件受 IO 影响。
-
三、 如何应对 Killed 状态的线程
-
理解: Killed 状态表示线程被标记终止,但仍在执行终止逻辑。
-
行动: 通过影响系统环境,帮助线程尽快完成终止逻辑。
-
如果是 innodb_thread_concurrency 问题: 临时调大参数或停止其他线程让出位置。
-
如果是回滚受 IO 限制: 减少系统压力。
-
-
结论: 进行相关优化后,只能等待流程自己完成。
四、 关于客户端的两个误解
-
误解一:库表多导致连接慢。
-
真相: 客户端连接成功后,默认会执行 show databases 和 show tables,并在本地构建哈希表用于自动补全。表越多,本地构建哈希表越慢。
-
解决: 连接时加上 -A 参数(关闭自动补全)或 -q/--quick 参数。
-
-
误解二:--quick 参数让服务端加速。
-
真相: --quick 参数使客户端采用不缓存方式接收结果(mysql_use_result)。
-
影响: 如果客户端处理慢,会阻塞服务端发送结果,可能降低服务端性能。
-
--quick 参数的真正含义: 让客户端更快。
-
跳过表名自动补全。
-
避免本地缓存大结果集耗费内存。
-
不记录命令到历史文件。
-
-
五、 小结
-
kill 命令不是强制停止,而是设置状态并唤醒线程。
-
线程需要执行到判断状态的“埋点”才能响应 kill。
-
终止逻辑本身需要时间完成。
-
Killed 状态表示线程正在执行终止逻辑。
-
应对 Killed 状态需要优化系统环境帮助线程完成。
-
客户端连接慢常是由于自动补全功能,--quick 参数是加速客户端,可能降低服务端性能。