背景
运维监控显示,线上环境Kafka上报上下线消息积压严重。此topic主要存储设备状态变化的消息,消费者负责消费更新MySQL数据库设备的状态。
排查步骤
由于只有这个topic积压严重,所以可以排除Kafka问题,我们首先排查了下MySQL侧。
1、查看MySQL正在运行的任务,执行如下命令:
show processlist;
一般来说通过此命令,可以看到正在运行的任务。可以发现明显耗时长的任务,直接看到SQL信息。本次执行的结果如下:

基本上都是空的连接,没有看到正在运行的比较耗时的任务。说明MySQL的压力不大。然后我们进行下一步排查。
2、是否存在资源竞争,锁表等问题。
查看是否锁表:
show OPEN TABLES where In_use > 0;
查看正在锁的事务:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
查看等待锁的事务:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS;
一般来说,通过1,2配合基本上能排查出具体的原因,定位到具体session的SQL,然后kill掉即可。但是这次运到的问题,很不一般。偶然的一个机会才定位出具体的原因。一直有这样的理解,只有update操作才会涉及到锁的,insert不会涉及锁的。查看官方文档有这样一段话,才恍然大悟:
INSERT sets an exclusive lock on the inserted row. This lock is an index-record lock, not a next-key lock (that is, there is no gap lock) and does not prevent other sessions from inserting into the gap before the inserted row.
Prior to inserting the row, a type of gap lock called an insert intention gap lock is set. This lock signals the intent to insert in such a way that multiple transactions inserting into the same index gap need not wait for each other if they are not inserting at the same position within the gap. Suppose that there are index records with values of 4 and 7. Separate transactions that attempt to insert values of 5 and 6 each lock the gap between 4 and 7 with insert intention locks prior to obtaining the exclusive lock on the inserted row, but do not block each other because the rows are nonconflicting.
If a duplicate-key error occurs, a shared lock on the duplicate index record is set. This use of a shared lock can result in deadlock should there be multiple sessions trying to insert the same row if another session already has an exclusive lock. This can occur if another session deletes the row.
大意如下:
INSERT在插入的行上设置排他锁。在插入行之前,会设置一种称为间隙锁(Gap Lock)。如果发生重复键错误,则会在重复索引记录上设置共享锁。如果另一个会话已经拥有排他锁,那么如果有多个会话尝试插入同一行,则使用共享锁可能会导致死锁。如果另一个会话删除了该行,就会发生这种情况。
先理清几个概念:
1、排他锁(X锁, exclusive locks)
如果事务对数据加上排他锁之后,则其他事务不能对该数据加任何的锁。获取排他锁的事务既能读取数据,也能修改数据。
2、共享锁(S锁, share locks)
其他事务可以读取数据,但不能对该数据进行修改,直到所有的共享锁被释放。
结合锁机制,梳理了下业务流程如下:

结论
由于共享锁的存在,直接导致会话A中的更新耗时增大,性能大幅下降。这只是初步分析,介于本人才疏学浅,难免有纰漏,欢迎一起讨论研究。
网友评论