首页 > 其他分享 >技术分享 | 死锁分析案例

技术分享 | 死锁分析案例

时间:2022-12-20 15:31:52浏览次数:68  
标签:08 hex token len asc 案例 死锁 分享 id


高鹏 爱可生开源社区 2019-08-16

作者:高鹏 

文章末尾有他著作的《深入理解MySQL主从原理 32讲》,深入透彻理解MySQL主从,GTID相关技术知识。

一、问题由来

这是我同事问我的一个问题,在网上看到了如下案例,本案例RC RR都可以出现,其实这个死锁原因也比较简单,我们来具体看看:

构造数据
 

CREATE database deadlock_test;
use deadlock_test;
CREATE TABLE `push_token` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`token` varchar(128) NOT NULL COMMENT 'push token',
`app_id` varchar(128) DEFAULT NULL COMMENT 'appid',
`deleted` tinyint(1) NOT NULL COMMENT '是否已删除 0:否 1:是',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_token_appid` (`token`,`app_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3384 DEFAULT CHARSET=utf8 COMMENT='pushtoken表';

insert into push_token (id, token, app_id, deleted) values(1,"token1",1,0);

操作数据

技术分享 | 死锁分析案例_MySQL

二、分析方法

我使用的分析方法是把整个加锁的日志打印出来,当然需要用到我自己做了输出修改的一个版本,如下:

​https://github.com/gaopengcarl/percona-server-locks-detail-5.7.22​

这个版本我打开了的日志记录参数如下:

mysql> show variables like '%gaopeng%';
+--------------------------------+-------+
| Variable_name | Value |
+--------------------------------+-------+
| gaopeng_mdl_detail | OFF |
| innodb_gaopeng_row_lock_detail | ON |
+--------------------------------+-------+
2 rows in set (0.01 sec)

这样大部分的Innodb加锁记录都会记录到errlog日志了。

好了下面我详细分析一下日志:

 

三、分析过程

初始化的情况整个表只有1条记录,本表包含一个主键和一个唯一键。

1. s1(TRX_ID367661)执行语句

begin;
UPDATE push_token SET deleted = 1 WHERE token = 'token1' AND app_id = '1';

日志输出:

2019-08-18T19:10:05.117317+08:00 6 [Note] InnoDB: TRX ID:(367661) table:deadlock_test/push_token index:uk_token_appid space_id: 449 page_id:4 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 6; hex 746f6b656e31; asc token1;;
1: len 1; hex 31; asc 1;;
2: len 8; hex 8000000000000001; asc ;;
2019-08-18T19:10:05.117714+08:00 6 [Note] InnoDB: TRX ID:(367661) table:deadlock_test/push_token index:PRIMARY space_id: 449 page_id:3 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000059c2c; asc ,;;
2: len 7; hex bf000000420110; asc B ;;
3: len 6; hex 746f6b656e31; asc token1;;
4: len 1; hex 31; asc 1;;
5: len 1; hex 80; asc ;;

我们看到主键和唯一键都加锁了,模式为LOCKX|LOCKNOT_GAP|如下图:

技术分享 | 死锁分析案例_分布式中间件_02

并且这个时候数据实际上是标记删除状态。

2. s2(TRX_ID367662) 执行语句

begin;DELETE FROM push_token WHERE id IN (1);

日志输出:

2019-08-18T19:10:22.751467+08:00 9 [Note] InnoDB: TRX ID:(367662) table:deadlock_test/push_token index:PRIMARY space_id: 449 page_id:3 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000059c2d; asc -;;
2: len 7; hex 400000002a1dc8; asc @ * ;;
3: len 6; hex 746f6b656e31; asc token1;;
4: len 1; hex 31; asc 1;;
5: len 1; hex 81; asc ;;
2019-08-18T19:10:22.752753+08:00 9 [Note] InnoDB: Trx(367662) is blocked!!!!!

这个时候S2需要获取主键上的:LOCKX|LOCKNOT_GAP| 锁,因此被堵塞了如下图:

技术分享 | 死锁分析案例_开源_03

 

3. s3(TRX_ID367663) 执行语句

begin; UPDATE push_token SET deleted = 1 WHERE token = 'token1' AND app_id = '1';

日志输出:

2019-08-18T19:10:30.822111+08:00 8 [Note] InnoDB: TRX ID:(367663) table:deadlock_test/push_token index:uk_token_appid space_id: 449 page_id:4 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 6; hex 746f6b656e31; asc token1;;
1: len 1; hex 31; asc 1;;
2: len 8; hex 8000000000000001; asc ;;
2019-08-18T19:10:30.918248+08:00 8 [Note] InnoDB: Trx(367663) is blocked!!!!!

这个时候S3需要获取唯一键上的LOCKX|LOCKNOT_GAP 锁,因此被堵塞了如下图:

技术分享 | 死锁分析案例_MySQL_04

 

4. s1(TRX_ID367661) 执行语句

这一步完成后死锁出现。

commit;

日志输出如下:

367663和367662各自获取需要的锁

2019-08-18T19:10:36.566733+08:00 8 [Note] InnoDB: TRX ID:(367663) table:deadlock_test/push_token index:uk_token_appid space_id: 449 page_id:4 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 6; hex 746f6b656e31; asc token1;;
1: len 1; hex 31; asc 1;;
2: len 8; hex 8000000000000001; asc ;;
2019-08-18T19:10:36.568711+08:00 9 [Note] InnoDB: TRX ID:(367662) table:deadlock_test/push_token index:PRIMARY space_id: 449 page_id:3 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000059c2d; asc -;;
2: len 7; hex 400000002a1dc8; asc @ * ;;
3: len 6; hex 746f6b656e31; asc token1;;
4: len 1; hex 31; asc 1;;
5: len 1; hex 81; asc ;;

367663获取主键锁堵塞、367662获取唯一键锁堵塞,死锁形成
2019-08-18T19:10:36.570313+08:00 8 [Note] InnoDB: TRX ID:(367663) table:deadlock_test/push_token index:PRIMARY space_id: 449 page_id:3 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 6; compact format; info bits 0
0: len 8; hex 8000000000000001; asc ;;
1: len 6; hex 000000059c2d; asc -;;
2: len 7; hex 400000002a1dc8; asc @ * ;;
3: len 6; hex 746f6b656e31; asc token1;;
4: len 1; hex 31; asc 1;;
5: len 1; hex 81; asc ;;
2019-08-18T19:10:36.571199+08:00 8 [Note] InnoDB: Trx(367663) is blocked!!!!!
2019-08-18T19:10:36.572481+08:00 9 [Note] InnoDB: TRX ID:(367662) table:deadlock_test/push_token index:uk_token_appid space_id: 449 page_id:4 heap_no:2 row lock mode:LOCK_X|LOCK_NOT_GAP|
PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 6; hex 746f6b656e31; asc token1;;
1: len 1; hex 31; asc 1;;
2: len 8; hex 8000000000000001; asc ;;
2019-08-18T19:10:36.573073+08:00 9 [Note] InnoDB: Transactions deadlock detected, dumping detailed information.

完成这一步 s1实际上释放了锁, 然后我们首先看到s2获取了主键上的LOCKX|LOCKNOTGAP锁,s3获取了唯一键上的LOCKX|LOCKNOTGAP 锁。但是随后s3获取主键上的LOCKX|LOCKNOTGAP锁堵塞,s2获取唯一键上的LOCKX|LOCKNOTGAP锁堵塞。因此死锁形成,如下图:

技术分享 | 死锁分析案例_数据库_05

好了我们看到了死锁就这样出现。整个分析过程我们只要看到加锁的日志实际上很容易就分析得出来。

标签:08,hex,token,len,asc,案例,死锁,分享,id
From: https://blog.51cto.com/u_15077536/5955954

相关文章

  • 技术分享 | MySQL 数据库如何改名?
    作者:杨涛涛资深数据库专家,专研MySQL十余年。擅长MySQL、PostgreSQL、MongoDB等开源数据库相关的备份恢复、SQL调优、监控运维、高可用架构设计等。目前任职于爱可生,为......
  • 技术分享 | percona QAN 介绍
    作者:孙健爱可生研发工程师,负责高可用组件相关开发。本文来源:原创投稿*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。一、背景QAN(QueryAna......
  • 技术分享 | MySQL 存储过程中的只读语句超时怎么办?
    作者:杨涛涛资深数据库专家,专研MySQL十余年。擅长MySQL、PostgreSQL、MongoDB等开源数据库相关的备份恢复、SQL调优、监控运维、高可用架构设计等。目前任职于爱可生,为......
  • 技术分享 | my2sql 与 binlog2sql 解析效率 battle
    作者:杨彩琳爱可生华东交付部DBA,主要负责MySQL日常问题处理及DMP产品支持。爱好跳舞,追剧。前言**大家在平时运维过程中应该都了解过或者使用过一些binlog解析工具,比如今天......
  • 故障分析 | MySQL 优化案例 - 字符集转换
    作者:xuty本文关键字:SQL优化、字符集一、背景Serverversion:5.7.24-logMySQLCommunityServer(GPL)开发联系我,说是开发库上有一张视图查询速度很慢,9000条数据要查10......
  • 故障分析 | MySQL 优化案例 - select count(*)
    作者:xuty本文关键字:count、SQL、二级索引一、故事背景项目组联系我说是有一张500w左右的表做selectcount(*)速度特别慢。二、原SQL分析Serverversion:5.7.24-logMy......
  • 技术分享 | 客户说 insert 慢,我该怎么办
    作者:张昊DBA,主要负责MySQL故障处理、DMP产品支持,擅长MySQL,喜欢打球,唱歌~。本文章比较侧重于分析流程,细节方面可能有所不足。唠嗑环节前段时间客户反馈有insert慢,查看slow......
  • 技术分享 | MySQL中一个聚类增量统计 SQL 的需求
    作者:刘晨网名bisal,具有十年以上的应用运维工作经验,目前主要从事数据库应用研发能力提升和技术管理相关的工作,OracleACE,腾讯云TVP,拥有OracleOCM&OCP、EXINDevOpsM......
  • 故障分析 | MySQL死锁案例分析
    一 背景死锁,其实是一个很有意思也很有挑战的技术问题,大概每个DBA和部分开发同学都会在工作过程中遇见过。本次分享的死锁案例更新不存在的记录加上XGAPlock和inser......
  • 直播报名|资深云原生架构师分享服务网格在腾讯 IT 业务的落地实践
    云原生在近几年的发展越来越火热,作为云上最佳实践而生的设计理念,也有了越来越多的实践案例,而一个个云原生案例的背后,是无声的巨大变革。腾讯云主办首个云原生百科知识直播......