Skip to content

Kill 命令

一、 kill 命令的执行过程

  • 大多数情况下有效: 例如长时间查询或锁等待。

  • 收到 kill 后线程的操作:

    • 设置线程状态为 THD::KILL_QUERY (或 THD::KILL_CONNECTION)。

    • 给执行线程发送信号,唤醒处于等待状态的线程。

  • 为什么不能立即停止?

    • 线程可能持有锁等资源,直接终止会导致资源泄露。

    • kill 命令类似 Linux 的信号,是通知进程/线程可以开始终止逻辑。

  • 终止过程的隐含逻辑:

    1. 语句执行过程中有“埋点”,判断线程状态是否为 THD::KILL_QUERY。

    2. 处于等待状态时,必须是可以被唤醒的等待(如锁等待使用 pthread_cond_timedwait)。

    3. 从进入终止逻辑到完成需要一个过程。

二、 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 限制: 减少系统压力。

  • 结论: 进行相关优化后,只能等待流程自己完成。

四、 关于客户端的两个误解

  1. 误解一:库表多导致连接慢。

    • 真相: 客户端连接成功后,默认会执行 show databases 和 show tables,并在本地构建哈希表用于自动补全。表越多,本地构建哈希表越慢。

    • 解决: 连接时加上 -A 参数(关闭自动补全)或 -q/--quick 参数。

  2. 误解二:--quick 参数让服务端加速。

    • 真相: --quick 参数使客户端采用不缓存方式接收结果(mysql_use_result)。

    • 影响: 如果客户端处理慢,会阻塞服务端发送结果,可能降低服务端性能。

    • --quick 参数的真正含义: 让客户端更快。

      • 跳过表名自动补全。

      • 避免本地缓存大结果集耗费内存。

      • 不记录命令到历史文件。

五、 小结

  • kill 命令不是强制停止,而是设置状态并唤醒线程。

  • 线程需要执行到判断状态的“埋点”才能响应 kill。

  • 终止逻辑本身需要时间完成。

  • Killed 状态表示线程正在执行终止逻辑。

  • 应对 Killed 状态需要优化系统环境帮助线程完成。

  • 客户端连接慢常是由于自动补全功能,--quick 参数是加速客户端,可能降低服务端性能。