写在前面:有时候安排好的计划总是没能如期完成,于是这篇文章就托在现在了!
一. 全局锁
-
什么是全局锁?
顾名思义,全局锁就是对整个数据库实例进行加锁,mysql提供了两种方法添加全局读锁:
a. Flush table with read lock(ftwrl)
b. set global readonly=true(一般不建议使用)
使用上述命令后,以下语句会被阻塞:数据更新语句(增,删,改),数据定义语句(建表,修改表结构)
b方式不建议使用的原因有两点:
第一点:在某些系统中,可能会根据 readonly 值做逻辑判断
第二点:在异常处理机制上有差异。对于方式a,如果客户端发生异常断开,MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。
而对于方式b,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。 -
为什么需要全局锁?
全局锁的典型使用场景是做全局逻辑备份(在主从多库的场景中使用可能会出现一定缺陷,由于本人暂时接触不多就不做讨论了) -
mysqldump
mysqldump是官方自带的逻辑工具,通过使用 -single-transation 来确保拿到一致性视图,由于MVCC特性,在备份过程可以正常更新.
这种方式相比于 ftwrl 性能更高,不过使用这种方式的前提是该引擎支持一致性隔离级别,像myisam引擎就无法使用了
二. 表锁
-
什么是表锁?
表锁的粒度精确到表级别,表锁的语法是 lock tables … read/write,相对应的解锁的语法是 unlock tables -
该不该使用表锁?
通常情况下,如果有更细粒度的锁的时候,我们尽量不要使用表级别锁来处理并发(innodb引擎有行级别锁),因为表级别锁对线上业务影响极大
三. MDL锁(metadata lock)
-
什么是MDL锁?
MDL是表锁中的一种,不需要显示的使用,在访问的时候会被自动加上;当对一个表做增删改查的时候会加 MDL读锁,当对表结构做变更的时候会加MDL写锁
a. 读锁之间不互斥,多个线程可以同时对一张表做增删改查
b. 读写锁,写锁之间是互斥的,如果有两个线程需要同时对一张表加字段,则其中一个需要等待另一个完成才能执行 -
MDL锁容易引发的问题:metadata lock wait
支持事务的 InnoDB 引擎表和 不支持事务的 MyISAM 引擎表,都会出现 Metadata Lock Wait 等待现象,
一旦出现 Metadata Lock Wait 等待现象,后续所有对该表的访问都会阻塞在该等待上,导致连接堆积,业务受影响。 -
多种场景容易引发 metadata lock
a. 有长时间运行的DML语句,这种情况会导致metadata lock等待,在工作中如果要对某个表进行DDL操作之前,
需要先用show processlist看看是否有长时间运行的SQL,防止出现线上故障。
b. 有未提交的事务,不管是select还是update,如果没有提交都会造成metadata lock等待。
c. 在执行期间失败的语句,不会立即释放metadata lock -
解决 metadata lock 方案
a. 一种是有长时间运行的DML语句的时候,这种情况要么kill掉DDL语句,要么就kill掉长时间运行的DML。
b. 另外一种情况是未提交的事务(正常的语句和失败的语句),这种情况要解决稍微复杂一点,需要找到对应没有提交的线程进行kill,或者kill掉DDL语句。
最快速的解决办法就是将所有sleep的线程都杀掉。
(备注:将所有sleep的线程都杀掉这个操作会导致没有提交的事务回滚,是有风险的,请根据业务场景进行操作)
上述多数内容借鉴学习有感于:
林晓斌老师mysql实战45讲
https://help.aliyun.com/knowledge_detail/41723.html
https://www.jianshu.com/p/e14c39e430bf