介绍
在MySQL中,当对某个进程执行Kill命令时,通过SHOW PROCESSLIST,在进程状态中会显示Killed情况。一般这个Killed状态是短暂的。但在某些情况下,Kill线程可能仍需要一些时间才能终止。如果该线程被其他线程锁定,则一旦其他线程释放其锁,Kill就会生效。
在MySQL中,Kill命令可以选择Connection 或 Query对象:
- Connection 在终止连接正在执行的任何语句后,它终止与给定processlist_id关联的连接。
- Query终止连接当前正在执行的语句,但保持连接本身不变。
Kill语句返回而不等待确认,但Kill标志检查会在相当短的时间内中止操作。中止操作以执行任何必要的清理也需要一些时间。当Kill线程进入处理状态,就会处于Killed状态,对于线程语句如以下处理方式:
- 对于SELECT操作期间,对于ORDER BY和GROUP BY循环,在读取行块后检查标记。如果设置了Kill标志,则语句将中止。
- 对于表执行ALTER TABLE操作会定期检查从原始表读取的每几行复制的终止标志。如果设置了Kill标志,则中止语句并删除临时表。(清理可能需要一些时间)
- 对于UPDATE或DELETE操作期间,每次读取块后以及每次更新或删除行后都会检查终止标志。如果设置了Kill标志,则语句将中止。如果不使用事务,则更改不会回滚。(清理可能需要一些时间)
- GET_LOCK()中止并返回NULL。
- 如果线程处于表锁处理程序中(状态:Locked),则表锁将迅速中止。
- 如果线程在写调用中等待可用磁盘空间,则写操作将中止,并显示“磁盘已满”错误消息。
- 对于EXPLAIN ANALYZE语句,中止并打印第一行输出。这在MySQL 8.0.20及更高版本中有效。
- 对于MyISAM表上,对于REPAIR TABLE或OPTIMIZE TABLE操作会导致表损坏且无法使用。(清理可能需要一些时间)
其实在MySQL客户段,常用的Ctrl + C操作就是 Kill Query操作,和手动执行kill query <query_id> 的效果是一样的。通过General日志记录,可以确认。
线程处于killed状态
对于一些长时间处于Killed状态的语句,通过SHOW PROCESSLIST查看。如下场景:
mysql> show processlist;
+------+-----------------+-----------+-----------+---------+------+----------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+-----------------+-----------+-----------+---------+------+----------------------------+------------------+
| 11 | event_scheduler | localhost | NULL | Daemon | 6912 | waiting for handler commit | NULL |
| 34 | root | localhost | db1 | Killed | 320 | System lock | load data infile '/tmp/emp.sql' |
| 5804 | root | localhost | employees | Query | 0 | init | show processlist |
+------+-----------------+-----------+-----------+---------+------+----------------------------+------------------+
3 rows in set (0.00 sec)
复制
也可以通过提供的视图去看执行情况:
#更改行trx_rows_modified指标,进行等待数值变成0
mysql> SELECT * FROM information_schema.INNODB_TRX\G
*************************** 1. row ***************************
trx_id: 407928
trx_state: RUNNING
trx_started: 2024-08-25 10:26:37
trx_requested_lock_id: NULL
trx_wait_started: NULL
trx_weight: 2
trx_mysql_thread_id: 0
trx_query: load data infile '/tmp/emp.sql'
trx_operation_state: NULL
trx_tables_in_use: 0
trx_tables_locked: 1
trx_lock_structs: 1
trx_lock_memory_bytes: 11281123
trx_rows_locked: 234343432
trx_rows_modified: 9928343
trx_concurrency_tickets: 0
trx_isolation_level: REPEATABLE READ
trx_unique_checks: 1
trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
trx_adaptive_hash_latched: 0
trx_adaptive_hash_timeout: 0
trx_is_read_only: 0
trx_autocommit_non_locking: 0
trx_schedule_weight: NULL
#TRANSACTIONS事务堵塞情况:
mysql> SHOW ENGINE INNODB STATUS\G
复制
对于执行时间过长,无法等待,需要在操作系统层面直接Kill -9 mysqld进程(慎用)。之后重新启动MySQL服务。
- 这时MySQL可能会进行Rollback操作 或 Commit操作。(绝大情况下都会进行Rollbackup)。
- 最好的办法就是等待InnoDB自己将事务进行回滚。
- 除此之外,也可以写入配置参数innodb_force_recovery=3不执行事务回滚操作(慎用)。
注意事项
- 大事务Kill操作需要很长时间,因为有进行回滚。有可能30分钟 或 几个小时。
- Kill connection操作会先断开网络连接,然后客户端会重新在一个线程发送Kill Query命令,show processlist会将kill connection的状态显示为Killed。然而其实InnoDB可能因为io繁忙,锁等待,并发线程数不够,而没有机会终止当前线程。出现这种情况,及时要腾出系统资源,比如IO,终止掉其他线程,增大innodb_thread_concurrency, 然后等待线程执行完毕。
- 并行读取参数innodb_parallel_read_threads当大于1,有可能会导致hang住线程(Bug).可以改成1.再观察
- 第三方备份软件xtrabackup终止一些语句 或 FTWRL命令导致hang住情况(Bug)。
总结
目前MySQL的Killed状态就像网上说的是“不死金身”。所以kill操作要谨慎使用。当使用Kill语句时,要关注这个线程情况。
如果出现长时间Killed状态,可以二次执行Kill命令,如还存在无法马上结束的情况,最快速的解决办法就是重启MySQL。因为有可能会导致底层数据页损坏,要有从节点提升主的准备。
此外,还应定期检查数据库的性能和资源使用情况,以便及时发现并解决问题。
参考
https://dev.mysql.com/doc/refman/8.4/en/general-thread-states.html
https://zhuanlan.zhihu.com/p/382578875
https://cloud.tencent.com/developer/article/1857161
评论


