背景
最近在忙着定制线上的监控,在忙到锁这里的时候,发现了一个奇怪的现象:
现象如下:
可以看到当前有很多锁等待(然后连续好几天观测都是2239),没有变化
[(none)]>show global status like 'Innodb_row_lock%';
+-------------------------------+-------------+
| Variable_name | Value |
+-------------------------------+-------------+
| Innodb_row_lock_current_waits | 2239 |
| Innodb_row_lock_time | 766556 |
| Innodb_row_lock_time_avg | 1505 |
| Innodb_row_lock_time_max | 52325 |
| Innodb_row_lock_waits | 3301 |
+-------------------------------+-------------+
5 rows in set (0.00 sec)
排查过程
首先说明一下几个变量值的含义:
`Innodb_row_lock_current_waits`:当前正在等待行锁的锁的数量
`Innodb_row_lock_time`:自系统启动以来等待锁的总时间(ms)
`Innodb_row_lock_time_avg`:每次等待锁的平均时间
`Innodb_row_lock_time_max`:等待锁的最大时间,基本等于锁超时的50s,这里有偏差是计算不一样导致
`Innodb_row_lock_waits`:自启动以来锁竞争的总次数
其他几个值都很正常,但是当前等待锁确实奇怪,业务也没有反馈相关超时,但是这个值一直没发生变化,本以为是瞬间,但是看监控,监控也一直没有发生变化:
所以开始进行了排查:
先说一下我的数据库版本是 percona 8.0.22
排查锁的方式之前有写过: 见锁排查方式
查询对应的几张表:
[information_schema]>select * from INNODB_TRX;
Empty set (0.00 sec)
[performance_schema]>select * from data_lock_waits;
Empty set (0.00 sec)
[performance_schema]>select * from data_locks;
Empty set (0.00 sec)
发现都是空的,根本没有锁等待
这里就彻底不知道怎么搞了,没有锁等待,那是不是这个值有问题:
去看了下源码,也比较简单。
if (thr->lock_state == QUE_THR_LOCK_ROW) {
srv_stats.n_lock_wait_count.inc();
srv_stats.n_lock_wait_current_count.inc();
if (thr->lock_state == QUE_THR_LOCK_ROW) {
const auto finish_time = ut_time_monotonic_us();
const uint64_t diff_time =
(finish_time > start_time) ? (uint64_t)(finish_time - start_time) : 0;
/current_lock 减/
srv_stats.n_lock_wait_current_count.dec();
srv_stats.n_lock_wait_time.add(diff_time);
…
可以看到就是简单的加减,所以怀疑是不是只加了没有正常减导致。
后来在网上搜索到了这个bug: 锁bug
最后这个bug提交者也是遇到了和我一样的问题,没有锁等待但是状态值却不准确。
但是因为很难复现,所以很尴尬。
最后又去找资深源码大佬八怪
老哥请教了一下:
这下也算是放心了。只取增量变化值进行监控。
最后
Innodb_row_lock_current_waits
:对于这个值,如果长时间很大,或者不变化,大家也不必着急,
只要自己的数据库系统中确实没有锁等待的话,那么监控就可以只取变化值
来监控,也欢迎
有遇到相同问题的或者找到问题的小伙伴留言交流。