概要描述
KunDB 中,当两个或多个事务永久阻塞并等待对方释放锁时,会发生死锁。此时可以选择终止其中一个事务来解除死锁。
本文介绍一种根据表名查找事务,并通过 kill process 解决死锁问题的一种方法
详细介绍
1、构造场景
创建一张有主键的表
CREATE TABLE testdum
(
id
int NOT NULL,
name
varchar(500) COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=InnoDB;
session1 | session2 | |
---|---|---|
1 | begin; | |
2 | insert into testdum (id ,name ) values (1,’aaaaaa’) on duplicate key update id=values(id),name=values(name); | |
3 | begin | |
4 | insert into testdum (id ,name ) values (1,’bbbbb’) on duplicate key update id=values(id),name=values(name); |
此时,session2中的这条insert
执行卡住,等待一个innodb_lock_wait_timeout
时长之后会报错:
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction (errno 1205) (sqlstate HY000) during query: insert into testdum (id ,name ) values (1,’bbbbb’) on duplicate key update id=values(id),name=values(name)
2、解决方案
最简便的解决方案(推荐):
select * from sys.innodb_lock_waits where locked_table_schema='db1' and locked_table_name='testdum';
直接拷贝 sql_kill_blocking_connection 的内容进行 kill即可。
注意! 高可用kundb可以在外层直接kill; 分布式kundb需连接到底层shard master 执行kill (先执行前面的select查询,确认在该shard 才需要执行。)
或者可以考虑 参考如下sql语句,获取thread_id
注意,可以根据
a.OBJECT_SCHEMA = 'db1' and a.OBJECT_NAME = 'testdum'
过滤表名
SELECT
NOW( 6 ) curr_dt,
a.thread_id,
b.PROCESSLIST_ID PROCESSLIST_ID,
ENGINE_TRANSACTION_ID trx_id,
object_name,
INDEX_NAME,
lock_type,
lock_mode,
lock_status,
LOCK_DATA,
c.BLOCKING_ENGINE_TRANSACTION_ID blk_trx_id,
c.BLOCKING_THREAD_ID blk_thd_id
FROM
PERFORMANCE_SCHEMA.data_locks a
LEFT JOIN PERFORMANCE_SCHEMA.threads b ON a.thread_id = b.thread_id
LEFT JOIN PERFORMANCE_SCHEMA.data_lock_waits c ON a.ENGINE_TRANSACTION_ID = c.REQUESTING_ENGINE_TRANSACTION_ID
AND a.thread_id = c.REQUESTING_THREAD_ID
WHERE
a.thread_id = b.thread_id
AND a.OBJECT_SCHEMA = 'db1'
AND a.OBJECT_NAME = 'testdum'
ORDER BY
thread_id,
trx_id;
可以看到WAITING
状态的这条sql,被BLOCKING_THREAD_ID
为2704的线程阻塞,而2704的PROCESSLIST_ID
为2646,
此时,可以执行kill
命令终止该进程。
kill 2646;
此时session1已处于杀死状态,无法再执行sql,再执行会报错 :
ERROR 2013 (HY000): EOF (errno 2013) (sqlstate HY000) during query: show tables kunErr(kungate: http://XXX:25001/)
session2再次执行可以运行成功。
FAQ
sys.innodb_lock_waits 视图的列及其含义如下:
sys.innodb_lock_waits:在MySQL 5.7中,这个视图简化了information_schema.innodb_lock_waits的使用,通过连接其他几个表来提供更直观的锁等待信息。在MySQL 8.0中,它进一步简化了视图定义,并且使用了performance_schema中的表来提供更详细的锁等待信息。
wait_started: 锁等待开始的时间。
wait_age: 锁等待的持续时间(以秒为单位)。
object_schema: 涉及的数据库名。
object_name: 涉及的表名。
index_name: 涉及的索引名。
lock_type: 锁类型(如 RECORD、TABLE 等)。
lock_mode: 锁模式(如 S、X、IS、IX 等)。
lock_status: 锁状态(如 GRANTED、WAITING)。
waiting_trx_id: 请求锁的事务 ID。
waiting_query: 请求锁的 SQL 查询。
waiting_pid: 请求锁的进程 ID。
waiting_lock_id: 请求的锁 ID。
waiting_lock_type: 请求的锁类型。
waiting_lock_mode: 请求的锁模式。
blocking_trx_id: 持有锁的事务 ID。
blocking_query: 持有锁的 SQL 查询。
blocking_pid: 持有锁的进程 ID。
blocking_lock_id: 被请求的锁 ID。
blocking_lock_type: 持有的锁类型。
blocking_lock_mode: 持有的锁模式。
sql_kill_blocking_query: 可以用来终止持有锁的查询的 SQL 命令。
sql_kill_blocking_connection: 可以用来终止持有锁的连接的 SQL 命令。