m6米乐安卓版下载-米乐app官网下载
暂无图片
12

dba-m6米乐安卓版下载

原创 1727 2023-07-04
1793

你的数据库是否出现过死锁
或者有没有可能出现了,你却不知道
110.png

就目前来看,业务使用mysql数据库能活过3、5年的,数据库是不可能 不出现死锁 情况的。即使你的数据库再健壮,开发随便事务 并发轻轻松松给你上锁,就看你能不能把握住了。
当然有同学可能说我们数据库就是稳定跑了3年,没有任何大的抖动,如果有死锁不早宕机或线上爆炸了
事实上非也,mysql很聪明,innodb_lock_wait_timeout

该参数是mysql innodb存储引擎中一个重要的系统变量,用于控制事务在等待锁定资源的时间超过设定值时的行为。具体来说,它规定了等待时间超过这个值的事务将会自动回滚。
该参数默认值是50s

所以不是你的数据库没有死锁,只是数据库本身帮你做了最极端的处理。
如何看懂死锁日志并分析死锁是如何造成的,是一个合格dba必备的技能
好吧让我们展开分析死锁日志的讲解

一、锁日志配置

默认情况下,log_error参数的值为空,此时mysql会将错误信息输出到标准错误流中,通常是屏幕或控制台。如果想将错误日志文件保存到特定路径,可以将该参数设置为指定的文件名或路径。
另外其他配置项也会影响错误日志的输出,通常需做如下配置:

log_error = /var/log/mysql/mysql_error.log
log_error_verbosity=3 (注意:这个参数很坑,设置为1、2时不会记录普通的死锁日志)
innodb_deadlock_detect=on
innodb_print_all_deadlocks=on

二、模拟死锁出现

1、建表:id主键、name普通索引

create table t
(
id int(11) not null auto_increment,
name varchar(255),
age int(11),
primary key(id),
key idx_name (name) using btree
);

2、插入模拟数据

insert into t(name,age) values(‘a’,11),(‘c’,12),(‘h’,13);
select * from t;
±—±-----±-----
| id | name | age |
±—±-----±-----
| 1 | a | 11 |
| 2 | c | 12 |
| 3 | h | 13 |
±—±-----±-----

3、环境准备

数据库隔离级别为rr(repeatable-read) 注意:不同隔离级别下加锁效果可能不同
自动提交关闭:set autocommit=0;

4、模拟并发
11.png

好的,现在已经成功模拟出了死锁冲突,在错误日志或执行 “show engine innodb status” 都可以看到。
至于这个过程中,发生了什么、产生了哪些锁、为什么造成了死锁,我们通过分析日志来为大家一步步进行讲解。

三、错误日志分析

全部错误日志内容如下

2023-06-28t01:53:46.216505z 0 [note] [my-012468] [innodb] transactions deadlock detected, dumping detailed information.
2023-06-28t01:53:46.216736z 0 [note] [my-012469] [innodb] *** (1) transaction:
transaction 3355, active 17 sec inserting
mysql tables in use 1, locked 1
lock wait 4 lock struct(s), heap size 1128, 4 row lock(s), undo log entries 2
mysql thread id 7, os thread handle 140183866210048, query id 19 localhost root update
insert into t(name,age) values(‘b’,20)
2023-06-28t01:53:46.216882z 0 [note] [my-012469] [innodb] *** (1) holds the lock(s):
record locks space id 10 page no 5 n bits 72 index idx_name of table test.t trx id 3355 lock_mode x
record lock, heap no 1 physical record: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
record lock, heap no 4 physical record: n_fields 2; compact format; info bits 0
0: len 1; hex 48; asc h;;
1: len 4; hex 80000003; asc ;;
2023-06-28t01:53:46.217257z 0 [note] [my-012469] [innodb] *** (1) waiting for this lock to be granted:
record locks space id 10 page no 5 n bits 72 index idx_name of table test.t trx id 3355 lock_mode x locks gap before rec insert intention waiting
record lock, heap no 3 physical record: n_fields 2; compact format; info bits 0
0: len 1; hex 43; asc c;;
1: len 4; hex 80000002; asc ;;
2023-06-28t01:53:46.217418z 0 [note] [my-012469] [innodb] *** (2) transaction:
transaction 3356, active 9 sec inserting
mysql tables in use 1, locked 1
lock wait 5 lock struct(s), heap size 1128, 4 row lock(s), undo log entries 2
mysql thread id 8, os thread handle 140183840720640, query id 20 localhost root update
insert into t(name,age) values(‘z’,100)
2023-06-28t01:53:46.217493z 0 [note] [my-012469] [innodb] *** (2) holds the lock(s):
record locks space id 10 page no 5 n bits 72 index idx_name of table test.t trx id 3356 lock_mode x
record lock, heap no 3 physical record: n_fields 2; compact format; info bits 0
0: len 1; hex 43; asc c;;
1: len 4; hex 80000002; asc ;;
2023-06-28t01:53:46.217650z 0 [note] [my-012469] [innodb] *** (2) waiting for this lock to be granted:
record locks space id 10 page no 5 n bits 72 index idx_name of table test.t trx id 3356 lock_mode x insert intention waiting
record lock, heap no 1 physical record: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
2023-06-28t01:53:46.217803z 0 [note] [my-012469] [innodb] *** we roll back transaction (1)

不要慌,一步一步来看

第一部分

注意关键字
(1) transaction

事务(1)信息
a.png
解读

transaction 3355 #是此事务的id
active 17 sec #活跃时间17秒
inserting #该事务当前正在运行的状态(可能的状态有fetching rows\updating\deleting\inserting等)
mysql tables in use 1, locked 1 #表示此事务涉及一个表,一个表里有锁(并不是说表锁的意思)
lock wait #表示事务正在等待锁
4 lock struct(s) #表示该事务的锁链表长度为4
heap size 1128 #为事务分配的锁堆内存大小
4 row lock(s) #表示当前事务持有的行锁个数,通过遍历上面提到的4个锁结构,找出其实类型为lock_rec的记录数。
undo log entries 2 #表示当前事务有2个undo log记录
mysql thread id 7 #这是线程id
os thread handle 140183866210048 #是操作系统线程的标识符
query id 19 #这是查询id
localhost root update #这是连接地址,用户,更新语句
insert into t(name,age) values(‘b’,20) #这是正在执行的sql

第二部分

注意关键字
(1) holds the lock(s)

事务(1)持有的锁
b.png
解读

record locks #表示持有的是行级锁
space id 10 page no 5 n bits 72 #space id为10\page no为5\n bits 72表示这个记录锁结构上留有72个bit位
index idx_name #表示锁的是idx_name索引
of table test.t #表示锁的具体是哪个表
trx id 3355 #事务id,和上面transaction相同
lock_mode x
#锁模式
记录锁(lock_rec_not_gap): lock_mode x locks rec but not gap
间隙锁(lock_gap): lock_mode x locks gap before rec
next-key 锁(lock_ornidary): lock_mode x
插入意向锁(lock_insert_intention): lock_mode x locks gap before rec insert intention
下面两个record lock…(注意看0开头的两行) #说明的是锁了哪些区间,这里有两个,(未知, ∞)和(未知,h)

第三部分

注意关键字
(1) waiting for this lock to be granted

事务(1)正在等待的锁
c.png
解读

基本和第二部内容相同
lock_mode x locks gap before rec #说明等待的是间隙锁
0: len 1; hex 43; asc c;; #说明正在等待的锁是(未知,c)

以上三部分就构成了事务1完整的日志信息

第四部分

注意关键字
(2) transaction

55.png
解读

事务2,依旧是由三部分组成,可以参照上面三部分来看,这里说一下重点内容
事务2正在执行的语句insert into t(name,age) values(‘z’,100)
事务2持有的锁:(未知,c)的间隙锁
事务2等待的锁:(未知, ∞)的间隙锁

第五部分
99.png
解读

事务1被回滚了

综合分析

现在结合我们上面模拟的两个事务来复盘一下
66.png
产生死锁过程分析:

事务1
update t set age=100 where name = ‘h’;

在rr隔离级别下为防止幻读所以会锁定索引的间隙,因此持有(c,h)和(h, ∞)的间隙锁,同时对修改的数据h持有记录锁,最终该语句持有(c,h]的临键锁 (h, ∞)的间隙锁

事务2
update t set age=99 where name = ‘c’;

同上,最终该语句持有(a,c]的临键锁 (c,h)的间隙锁
注意!!!这里可能有同学疑惑,事务1已经有了(c,h]的临键锁为什么事务2还可以获取(c,h)的间隙锁
有疑惑的同学请参考innodb存储引擎锁兼容性
77.png
88.png
我们继续

事务1
insert into t(name,age) values(‘b’,20);

需要(a,c)的插入意向锁,但是该锁已经被事务2拿了,所以此时事务1阻塞等待

事务2
insert into t(name,age) values(‘z’,100);

需要(h, ∞)的插入意向锁,但是该锁已经被事务1拿了,所以此时事务2阻塞等待
好的,现在由于事务1和事务2都在等待彼此的锁而造成死锁了
但是我们看到的现象为什么是事务2直接插入成功了,事务1报错了
这是因为当形成死锁闭环后,innodb底层的机制会让其中一个事务让出资源,另外的事务执行成功
这也就是错误日志中“第五部分”解读的答案
好,现在本着事后诸葛亮的态度来看,死锁日志的内容和我们模拟的操作完全吻合,同理,当我们先看到死锁日志也可以回溯出整个死锁过程。

总结

百因必有果,不是你的数据库一点问题都没有,只是mysql本身就很强大。
当然,对死锁的诊断不能仅仅靠死锁日志,还应该结合应用程序的代码来进行分析。大多数情况下,每个事务都不止一条sql,我们甚至需要结合当时的binlog来分析到底是事务中的哪个事件间冲突了,同时要对加锁流程深入学习了解才可能分析出死锁的根源。

最后修改时间:2023-12-27 10:29:23
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【米乐app官网下载的版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论

网站地图