应用-flush table with read lock 全局读锁定位
找出谁持有全局读锁
全局读锁通常是由flush table with read lock;这类语句添加的。在各种备份工具为了得到一致性备份,已经在具备主从复制架构的环境中做主备切换时常常使用这类语句。另外还有一种情况,可是最难排查的一种情况,就是线上系统全局约束不规范,各种人员使用的数据库账号都拥有RELOAD权限,都可以对数据库加全局读锁。
在MySQL5.7之前的版本中,要排查谁持有全局读锁,通常在数据库层面是很难直接查询到有用数据的(innodb_locks表也只能记录InnoDB层面的锁信息,而全局读锁是Server层面的锁,所以无法查询到)。从MySQL5.7版本开始提供了performance_schema.metadata_locks表,用来记录一些Server层的锁信息(包含全局读锁和MDL锁等)。
下面通过一个示例来演示如何使用performance_schema找出谁持有全局读锁。
首先,开启一个会话,执行加全局读锁的语句。
# 执行加锁语句 mysql> flush table with read lock; Query OK, 0 rows affected (0.60 sec) # 查询以下加锁线程的process id,以使与后续排查过程对应 mysql> select connection_id(); +-----------------+ | connection_id() | +-----------------+ | 4 | +-----------------+ 1 row in set (0.00 sec)
然后开启第二个会话,执行可能对数据在成修改的任意语句,以update操作为例:
mysql> select * from a limit 1\G *************************** 1. row *************************** id: 1 k: 2523 c: 66732467966-31166435533-24160857174-47700857015-95528431613-72420310257-00729886733-14082739850-34910057147-23412468124 pad: 69449313224-10645335122-68404111484-06065403356-59643719520 1 row in set (0.00 sec) mysql> select connection_id(); +-----------------+ | connection_id() | +-----------------+ | 5 | +-----------------+ 1 row in set (0.00 sec) update a set id = '111111' where id = 1; ## 此时操作被阻塞
接下来,开启第三个会话,开始使用一些手段进行排查
mysql> show processlist; +----+------+-----------+------+---------+------+------------------------------+-----------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+------+-----------+------+---------+------+------------------------------+-----------------------------------------+ | 4 | root | localhost | wjj | Sleep | 121 | | NULL | | 5 | root | localhost | wjj | Query | 12 | Waiting for global read lock | update a set id = '111111' where id = 1 | | 6 | root | localhost | NULL | Query | 0 | starting | show processlist | +----+------+-----------+------+---------+------+------------------------------+-----------------------------------------+ 3 rows in set (0.00 sec) mysql> select connection_id(); +-----------------+ | connection_id() | +-----------------+ | 6 | +-----------------+ 1 row in set (0.00 sec)
查询processlist信息,这里只能看到process id为5的线程State为Waiting for global read lock;表示正在等待全局读锁
mysql> select * from information_schema.innodb_locks; Empty set, 1 warning (0.05 sec) Warning (Code 1681): 'INFORMATION_SCHEMA.INNODB_LOCKS' is deprecated and will be removed in a future release. mysql> select * from information_schema.innodb_lock_waits; Empty set, 1 warning (0.00 sec)
Warning (Code 1681): 'INFORMATION_SCHEMA.INNODB_LOCK_WAITS' is deprecated and will be removed in a future release. mysql> select * from information_schema.innodb_trx; Empty set (0.00 sec) show engine innodb status\G 仍然查不到
从5.7开始提供了performance_schema.metadata_locks,该表记录了各种Server层的锁信息,包括全局读锁和MDL锁等信息
mysql> select * from performance_schema.metadata_locks where owner_thread_id !=sys.ps_thread_id(connection_id()); +-------------+---------------+-------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID | +-------------+---------------+-------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ | GLOBAL | NULL | NULL | 140473091514592 | SHARED | EXPLICIT | GRANTED | | 30 | 1594 | | COMMIT | NULL | NULL | 140473080812752 | SHARED | EXPLICIT | GRANTED | | 30 | 1727 | | GLOBAL | NULL | NULL | 140473079550816 | INTENTION_EXCLUSIVE | STATEMENT | PENDING | | 31 | 1132 | +-------------+---------------+-------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ 3 rows in set (0.00 sec) mysql> select * from performance_schema.metadata_locks ; +-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ | OBJECT_TYPE | OBJECT_SCHEMA | OBJECT_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE | LOCK_DURATION | LOCK_STATUS | SOURCE | OWNER_THREAD_ID | OWNER_EVENT_ID | +-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ | GLOBAL | NULL | NULL | 140473091514592 | SHARED | EXPLICIT | GRANTED | | 30 | 1594 | | COMMIT | NULL | NULL | 140473080812752 | SHARED | EXPLICIT | GRANTED | | 30 | 1727 | | GLOBAL | NULL | NULL | 140473079550816 | INTENTION_EXCLUSIVE | STATEMENT | PENDING | | 31 | 1132 | | TABLE | performance_schema | metadata_locks | 140473280831248 | SHARED_READ | TRANSACTION | GRANTED | | 32 | 342 | +-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+ 4 rows in set (0.00 sec)
持有锁的内存线程ID为30,被阻塞的内部线程ID为31。
如果是生产环境,综合上述信息,通过在proecss id值对应的User、Host、db信息,大致判断属于什么业务用户,找相关人员询问清楚,再进行处理。
mysql> select THREAD_ID,PROCESSLIST_ID,THREAD_OS_ID from performance_schema.threads; +-----------+----------------+--------------+ | THREAD_ID | PROCESSLIST_ID | THREAD_OS_ID | +-----------+----------------+--------------+ | 1 | NULL | 1560 | .......... | 24 | NULL | 1584 | | 25 | NULL | 1583 | | 26 | NULL | 1587 | | 27 | 1 | 1588 | | 30 | 4 | 1593 | | 31 | 5 | 2636 | | 32 | 6 | 2651 | +-----------+----------------+--------------+ 28 rows in set (0.00 sec)
查询全局读锁阻塞者脚本
select /*查询全局读锁阻塞者脚本*/ p.THREAD_ID, l.ID as processlist_id, p.event_name, round(p.TIMER_WAIT / 1000 / 1000 / 1000 /1000,2) as "TIMER_WAIT(s)", p.CURRENT_SCHEMA, p.SQL_TEXT, l.host, l.DB, l.STATE, ml.LOCK_TYPE, ml.LOCK_DURATION, ml.LOCK_STATUS, ml.OWNER_EVENT_ID from performance_schema.events_statements_current p inner join performance_schema.metadata_locks ml inner join information_schema.PROCESSLIST l on ml.OWNER_THREAD_ID = p.THREAD_ID and sys.ps_thread_id(l.id) = ml.OWNER_THREAD_ID and ml.OWNER_THREAD_ID != sys.ps_thread_id(connection_id());
浙公网安备 33010602011771号