• 死锁分析-(DML+DDL触发Server层死锁)


     
    参考文档:
    MySQL Server层的锁信息比innodb存储引擎层略复杂,而且Server层的死锁信息不做记录。
    提示:show engine innodb status; 只能查看Innodb存储引擎层的死锁信息
    内核月报(MDL加锁源码分析):
    http://mysql.taobao.org/monthly/2018/02/01/
    object上已持有锁和请求锁的兼容性矩阵如下。
    Request   |  Granted requests for lock                  |
     type     | S  SH  SR  SW  SWLP  SU  SRO  SNW  SNRW  X  |
    ----------+---------------------------------------------+
    S         | +   +   +   +    +    +   +    +    +    -  |
    SH        | +   +   +   +    +    +   +    +    +    -  |
    SR        | +   +   +   +    +    +   +    +    -    -  |
    SW        | +   +   +   +    +    +   -    -    -    -  |
    SWLP      | +   +   +   +    +    +   -    -    -    -  |
    SU        | +   +   +   +    +    -   +    -    -    -  |
    SRO       | +   +   +   -    -    +   +    +    -    -  |
    SNW       | +   +   +   -    -    -   +    -    -    -  |
    SNRW      | +   +   -   -    -    -   -    -    -    -  |
    X         | -   -   -   -    -    -   -    -    -    -  |
     
     
     
     
    环境说明:
    为了更好的说明整个过程,数据库在启动时需要开启 performance_schema 参数,开启 MDL 锁的相关监控数据。
    #确认 performance_schema 参数已经打开。
    mysql> show global variables like 'performance_schema';
    +--------------------+-------+
    | Variable_name | Value |
    +--------------------+-------+
    | performance_schema | ON |
    +--------------------+-------+
    1 row in set (0.00 sec)
     
    #开启 MDL 锁的相关监控数据。
    mysql> UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl';
    Query OK, 0 rows affected (0.00 sec)
    Rows matched: 1 Changed: 0 Warnings: 0
     
     
    #创建测试数据
    mysql> create table t_lock (id int primary key auto_increment,
    -> name varchar(20));
    Query OK, 0 rows affected (0.01 sec)
     
     
    mysql> insert into t_lock(id,name) values(1,'张三'),(2,'李四'),(3,'王五'),(4,'赵六');
    Query OK, 4 rows affected (0.00 sec)
    Records: 4 Duplicates: 0 Warnings: 0
     
    复现死锁过程(提前开启3个mysql会话):
    session1(只进行查询),session3(查询持有的MDL):
    #session1
    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> select * from t_lock;
    +----+--------+
    | id | name |
    +----+--------+
    | 1 | 张三 |
    | 2 | 李四 |
    | 3 | 王五 |
    | 4 | 赵六 |
    +----+--------+
    4 rows in set (0.00 sec)
     
    #session3 OWNER_THREAD_ID 46 这条记录忽略掉,是session3持有的MDL锁
    OWNER_THREAD_ID = 45 这条记录是session1
    LOCK_TYPE = SHARED_READ 持有锁类型
    LOCK_STATUS = GRANTED 锁状态已经是待有状态
     
    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 |
    +-------------+--------------------+----------------+-----------------------+-------------+---------------+-------------+--------+-----------------+----------------+
    | TABLE | ceshi | t_lock | 139765484063408 | SHARED_READ | TRANSACTION | GRANTED | | 45 | 30 |
    | TABLE | performance_schema | metadata_locks | 52674736 | SHARED_READ | TRANSACTION | GRANTED | | 46 | 3 |
    +-------------+--------------------+----------------+-----------------------+-------------+---------------+-------------+--------+-----------------+----------------+
    2 rows in set (0.00 sec)
    session2(进行DDL操作),session3(查询持有的MDL):
     
    #session3 OWNER_THREAD_ID 46 这条记录忽略掉,是session3持有的MDL锁
    OWNER_THREAD_ID = 45 这条记录是session1的,暂时忽略掉。
    从结果看,session2执行的DDL命令,
    获取了 GLOBAL 的INTENTION_EXCLUSIVE (全局意向排它锁)
    获取了 schema 为 ceshi 的INTENTION_EXCLUSIVE (ceshi 库的意向排它锁)
    获取了 ceshi.t_lock 对象 的SHARED_UPGRADABLE (ceshi.t_lock 的升级锁)
    等待获取 ceshi.t_locK 对象的EXCLUSIVE (等待获取ceshi.t_lock排它锁,LOCK_STATUS 状态是PENDING)
    #session2
    mysql> alter table t_lock add age int;
    ...命令会卡住,在等待
     
     
    #session3
    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 |
    +-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+
    | TABLE | ceshi | t_lock | 139765484063408 | SHARED_READ | TRANSACTION | GRANTED | | 45 | 30 |
    | GLOBAL | NULL | NULL | 139766032053392 | INTENTION_EXCLUSIVE | STATEMENT | GRANTED | | 47 | 21 |
    | SCHEMA | ceshi | NULL | 139766031949536 | INTENTION_EXCLUSIVE | TRANSACTION | GRANTED | | 47 | 21 |
    | TABLE | ceshi | t_lock | 139766032048752 | SHARED_UPGRADABLE | TRANSACTION | GRANTED | | 47 | 21 |
    | TABLE | ceshi | t_lock | 139766031960848 | EXCLUSIVE | TRANSACTION | PENDING | | 47 | 21 |
    | TABLE | performance_schema | metadata_locks | 52674736 | SHARED_READ | TRANSACTION | GRANTED | | 46 | 4 |
    +-------------+--------------------+----------------+-----------------------+---------------------+---------------+-------------+--------+-----------------+----------------+
    6 rows in set (0.00 sec)
    在session1 执行一个update命令,复现死锁。
    session1 的事务被回滚,
    session2 的DDL命令成功执行。
    #session1
    mysql> begin;
    Query OK, 0 rows affected (0.00 sec)
     
    mysql> select * from t_lock;
    +----+--------+
    | id | name |
    +----+--------+
    | 1 | 张三 |
    | 2 | 李四 |
    | 3 | 王五 |
    | 4 | 赵六 |
    +----+--------+
    4 rows in set (0.00 sec)
     
    mysql> update t_lock set id=100 where id=1;
    ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
     

    #session2
    
    
    mysql> alter table t_lock add age int;
    
    
    Query OK, 0 rows affected (27 min 2.98 sec)
    
    
    Records: 0 Duplicates: 0 Warnings: 0
     
     
     
    死锁分析:
    根据之前的锁兼容矩阵图,X锁和任何锁是不兼容的。
     
    session1: 开启事务,并执行查询,持有 ceshi.t_lock 对象的 SHARED_READ 锁,简称SR锁。
    session2:执行DDL命令,想要获取 ceshi.t_lock 对象的 EXCLUSIVE 锁,简称X锁。
     
    这个状态时,session2 在等 session1 释放锁。
     
    sessin1: 继续执行 update 命令,会申请 ceshi.t_lock 对象的 SHARED_WRITE 锁,简称SW锁。
    这个状态时,session2 在等待获取 ceshi.t_lock 对象的X锁,session1 想要申请SW锁,必须等session2 释放掉锁。
    所以 session1 在等 session2 释放锁。
     
    两个会话互相等待,发生死锁,MySQL数据库会自动回滚其中一个事务。
     
  • 相关阅读:
    [zz] 从VMM中终止GUEST OS中运行进程
    [zz]Linux流量监控工具 – iftop (最全面的iftop教程)
    [zz]Ubuntu终端下Nethogs网络流量监控工具
    AtomicBoolean运用
    JDK中的URLConnection参数详解
    java读取文本文件数据
    tomcat时区设置
    java的upload
    java复习(set 、list、map)
    NIO学习笔记1
  • 原文地址:https://www.cnblogs.com/nanxiang/p/15078847.html
Copyright © 2020-2023  润新知