当前位置:网站首页>MySQL45讲——学习极客时间MySQL实战45讲笔记—— 06 | 全局锁和表锁_给表加个字段怎么有这么多阻碍
MySQL45讲——学习极客时间MySQL实战45讲笔记—— 06 | 全局锁和表锁_给表加个字段怎么有这么多阻碍
2022-07-04 12:44:00 【Alascanfu】
本文目录
06 | 全局锁和表锁_给表加个字段怎么有这么多阻碍
本文是 MySQL 实战 45 讲 (geekbang.org) 的学习笔记
请各位一定要支持作者大大,写的太棒了~
这里只是小付对文章学习的笔记~
也可以免费学习五小节哦~
MySQL 锁
数据库锁设计的初衷是处理并发问题作为多用户共享的资源,当出现并发访问的时候,数据库就需要合理地控制资源的访问规则。而锁就是用来实现这些访问规则的重要数据结构。
根据加锁的范围,MySQL 里面的锁大致可以分成全局锁、表级锁和行锁三类。
今天这篇文章,我会和你分享全局锁和表级锁。
全局锁
什么是全局锁?
全局锁就是对整个数据库实例加锁。
如何全局加锁?
MySQL 提供了一个加全局读锁的方法,命令是 Flush tables with read lock (FTWRL)
。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句DML(数据的增删改)、数据定义语句DDL(包括建表、修改表结构等)和更新类事务的提交语句。
什么时候会用到全局锁?
全局锁的典型使用场景是——做全库逻辑备份。
也就是把整个库的每张表 select 出来存成文本。
以前有一种做法,是通过 FTWRL 确保不会有其他线程对数据库做更新,然后对整个库做备份。注意,在备份过程中整个库完全处于只读状态。
全局锁带来的危害
1️⃣ 如果你在 主库 上进行全局锁备份,那么备份期间都不能执行更新,业务基本上就得停摆。
2️⃣ 如果你在 从库 上进行全局锁备份,那么备份期间从库不能执行主库同步过来的 binlog(归档日志)会导致主从延迟。
为什么备份要加锁?不加锁会有什么问题?
举个
假设你现在要维护“极客时间”的购买系统,关注的是用户账户余额表和用户课程表。
现在发起一个逻辑备份。假设备份期间,有一个用户,他购买了一门课程,业务逻辑里就要扣掉他的余额,然后往已购课程里面加上一门课。
如果时间顺序上是先备份账户余额表 (u_account),然后用户购买,然后备份用户课程表 (u_course),会怎么样呢?你可以看一下这个图:
可以看到,这个备份结果里,用户 A 的数据状态是“账户余额没扣,但是用户课程表里面已经多了一门课”。如果后面用这个备份来恢复数据的话,用户 A 就发现,自己赚了。
当然事事都有对立性,如果先备份的用户课程表(u_course) 那么你就会神奇的发现——钱扣了,课却并没有加入到你的课程表当中。
也就是说,不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。
此时就发生了前后数据不一致的情况。
说到视图你肯定想起来了,我们在前面讲事务隔离的时候,其实是有一个方法能够拿到一致性视图的,对吧?
是的,就是在可重复读隔离级别(RR)下开启一个事务。
官方自带的逻辑备份工具是 mysqldump。当 mysqldump 使用参数–single-transaction
的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于 MVCC 的支持,这个过程中数据是可以正常更新的。
此时你就会存有疑惑了——有了MVCC的支持,为什么还需要 FTWRL 呢?
一致性读是好,但前提是引擎要支持这个隔离级别
比如,对于 MyISAM 这种不支持事务的引擎,如果备份过程中有更新,总是只能取到最新的数据,那么就破坏了备份的一致性。这时,我们就需要使用 FTWRL 命令了。
注意点:
1️⃣ single-transaction 方法只适用于所有的表使用事务引擎的库
2️⃣ 如果有的表使用了不支持事务的引擎,那么备份就只能通过 FTWRL 方法。这往往是 DBA 要求业务开发人员使用 InnoDB 替代 MyISAM 的原因之一。
既然全库只读,为什么不使用 set global readonly=true 的方式呢?
确实 readonly 方式也可以让全库进入只读状态,但我还是会建议你用 FTWRL 方式,主要有两个原因:
1️⃣ 在有些系统中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式影响面更大,我不建议你使用。
2️⃣ 在异常处理机制上有差异。如果执行 FTWRL 命令之后由于客户端发生异常断开,那么 MySQL 会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为 readonly 之后,如果客户端发生异常,则数据库就会一直保持 readonly 状态,这样会导致整个库长时间处于不可写状态,风险较高。
业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)。不论是哪种方法,一个库被全局锁上以后,你要对里面任何一个表做加字段操作,都是会被锁住的。
表级锁
MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。
表锁
表锁的语法是
lock tables … read/write
。
与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放.
注意点:
1️⃣ lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
举个
如果在某个线程 A 中执行 lock tables t1 read, t2 write;
这个语句,则其他线程写 t1、读写 t2 的语句都会被阻塞。
同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许,自然也不能访问其他表
小结:写是排他锁,写锁意味着其他线程不能读也不能写。读锁是共享锁,加上后其他锁只能读不能写,本线程也不能写
在还没有出现更细粒度的锁的时候,表锁是最常用的处理并发的方式。而对于 InnoDB 这种支持行锁的引擎,一般不使用 lock tables 命令来控制并发,毕竟锁住整个表的影响面还是太大。
MDL(元数据锁)
MDL 不需要显式使用,在访问一个表的时候会被自动加上。MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。
- 在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。
1️⃣ 读锁之间并不互斥,因此你可以有多个线程同时对一张表增删改查。
2️⃣ 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。
虽然 MDL 锁是系统默认会加的,但却是你不能忽略的一个机制。比如下面这个例子,我经常看到有人掉到这个坑里:给一个小表加个字段,导致整个库挂了。
举个
给一个表加字段,或者修改字段,或者加索引,需要扫描全表的数据。
索引要根据表中的每一行的记录值来创建,所以需要全表扫描;加字段或修改字段,也要修改每一行记录中的对应列的数据,所以也要全表扫描
** 注意点:**实际上,即使是小表,操作不慎也会出问题。我们来看一下下面的操作序列,假设表 t 是一个小表。
正常流程如下:
A(读锁) - > B(读锁) - > C(申请写锁(写锁等待) block) - > D(申请读锁,因为写锁等待,阻塞) - > A,B(Commit) - > C(得到写锁) - > D(申请读锁 block) - > C(ddl online 写锁蜕化读锁) - > D(得到读锁) - > C(升级写锁 block By D) - > D(commit,读锁释放) - > C(完成ddl ,释放写锁)
ps:申请MDL锁的操作会形成一个队列 ,写锁申请 优先级高于 读锁
1️⃣ 我们可以看到 session A 先启动,这时候会对表 t 加一个 MDL 读锁。由于 session B 需要的也是 MDL 读锁,因此可以正常执行。
2️⃣ 之后 session C 会被 blocked,是因为 session A 的 MDL 读锁还没有释放,而 session C 需要 MDL 写锁,因此只能被阻塞。
3️⃣ 如果只有 session C 自己被阻塞还没什么关系,但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被 session C 阻塞。前面我们说了,所有对表的增删改查操作都需要先申请 MDL 读锁,就都被锁住,等于这个表现在完全不可读写了。
4️⃣ 如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新 session 再请求的话,这个库的线程很快就会爆满。你现在应该知道了,事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。
如何安全地给小表加字段?
1️⃣ 首先我们要解决长事务,事务不提交,就会一直占着 MDL 锁。在 MySQL 的 information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。
如果你要变更的表是一个热点表,虽然数据量不大,但是上面的请求很频繁,而你不得不加个字段,你该怎么做呢?
在 alter table
语句里面设定等待时间,如果**在这个指定的等待时间里面能够拿到 MDL 写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。**之后开发人员或者 DBA 再通过重试命令重复这个过程。
ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ...
小结
1️⃣ 全局锁主要用在逻辑备份过程中。对于全部是 InnoDB 引擎的库,我建议你选择使用–single-transaction
参数,对应用会更友好。
2️⃣ **表锁一般是在数据库引擎不支持行锁的时候才会被用到的。**如果你发现你的应用程序里有 lock tables 这样的语句,你需要追查一下,比较可能的情况是:
要么是你的系统现在还在用 MyISAM 这类不支持事务的引擎,那要安排升级换引擎;
要么是你的引擎升级了,但是代码还没升级。我见过这样的情况,最后业务开发就是把 lock tables 和 unlock tables 改成 begin 和 commit,问题就解决了。
注意点:
1️⃣ 原本需要用到表锁的场景都可以直接用事务替代,因为事务自动添加 MDL 锁,MDL 锁能够区别对待表结构的修改和普通增删改查,粒度更细。
课后题
备份一般都会在备库上执行,你在用–single-transaction 方法做逻辑备份的过程中,如果主库上的一个小表做了一个 DDL,比如给一个表上加了一列。这时候,从备库上会看到什么现象呢?
1️⃣ 情况1: master上对小表t1的DDL传输到slave去应用的时刻,mysqldump已经备份完了t1表的数据,此时slave 同步正常,不会有问题。
2️⃣ 情况2:master上对小表t1的DDL传输到slave去应用的时刻,mysqldump正在备份t1表的数据,此时会发生MDL 锁,从库上t1表的所有操作都会阻塞住。主从延迟,直到 Q6 执行完成。
3️⃣ 情况3: master 上对小表t1的DDL传输到slave去应用的时刻,mysqldump 还没对t1表进行备份,该DDL会在slave的t1表应用成功,但是当导出到t1表的时候会报“ERROR 1412 (HY000): Table definition has changed, please retry transaction” 错误,导致导出失败!
本节总结
总结: 根据加锁范围:MySQL里面的锁可以分为:全局锁、表级锁、行级锁、
一、全局锁:
对整个数据库实例加锁。
MySQL提供加全局读锁的方法:Flush tables with read lock(FTWRL) 这个命令可以使整个库处于只读状态。使用该命令之后,数据更新语句、数据定义语句和更新类事务的提交语句等操作都会被阻塞。
使用场景:全库逻辑备份。
风险:
1.如果在主库备份,在备份期间不能更新,业务停摆
2.如果在从库备份,备份期间不能执行主库同步的binlog,导致主从延迟
官方自带的逻辑备份工具mysqldump,当mysqldump使用参数–single-transaction的时候,会启动一个事务,确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。
一致性读是好,但是前提是引擎要支持这个隔离级别。
如果要全库只读,为什么不使用set global readonly=true的方式?
1.在有些系统中,readonly的值会被用来做其他逻辑,比如判断主备库。所以修改global变量的方式影响太大。
2.在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。
二、表级锁
MySQL里面表级锁有两种,一种是表锁,一种是元数据所(meta data lock,MDL)
表锁的语法是:lock tables … read/write
可以用unlock tables主动释放锁,也可以在客户端断开的时候自动释放。
lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。
对于InnoDB这种支持行锁的引擎,一般不使用lock tables命令来控制并发,毕竟锁住整个表的影响面还是太大。
MDL:不需要显式使用,在访问一个表的时候会被自动加上。
MDL的作用:保证读写的正确性。
在对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。
读锁之间不互斥。读写锁之间,写锁之间是互斥的,用来保证变更表结构操作的安全性。
MDL 会直到事务提交才会释放,在做表结构变更的时候,一定要小心不要导致锁住线上查询和更新。
边栏推荐
- Etcd storage, watch and expiration mechanism
- Simple understanding of binary search
- Interviewer: what is the difference between redis expiration deletion strategy and memory obsolescence strategy?
- Apache服务器访问日志access.log设置
- 从0到1建设智能灰度数据体系:以vivo游戏中心为例
- Optional values and functions of the itemized contenttype parameter in the request header
- 《预训练周刊》第52期:屏蔽视觉预训练、目标导向对话
- Introduction to XML III
- C#/VB. Net to add text / image watermarks to PDF documents
- Runc hang causes the kubernetes node notready
猜你喜欢
unity不识别rider的其中一种解决方法
Dgraph: large scale dynamic graph dataset
Meituan Ali's Application Practice on multimodal recall
[cloud native | kubernetes] in depth understanding of ingress (12)
CVPR 2022 | TransFusion:用Transformer进行3D目标检测的激光雷达-相机融合
Oracle was named the champion of Digital Innovation Award by Ventana research
Building intelligent gray-scale data system from 0 to 1: Taking vivo game center as an example
Personalized online cloud database hybrid optimization system | SIGMOD 2022 selected papers interpretation
CANN算子:利用迭代器高效实现Tensor数据切割分块处理
Flet教程之 03 FilledButton基础入门(教程含源码)(教程含源码)
随机推荐
高效!用虚拟用户搭建FTP工作环境
Cann operator: using iterators to efficiently realize tensor data cutting and blocking processing
Annual comprehensive analysis of China's mobile reading market in 2022
请问大佬们有遇到这个情况吗,cdc 1.4 连接MySQL 5.7 无法使用 timestamp
.NET 使用 redis
AI 绘画极简教程
Reptile exercises (I)
Node の MongoDB 安装
Node mongodb installation
比量子化学方法快六个数量级,一种基于绝热状态的绝热人工神经网络方法,可加速对偶氮苯衍生物及此类分子的模拟
mysql三级分销代理关系存储
8 expansion sub packages! Recbole launches 2.0!
模块化笔记软件综合评测:Craft、Notion、FlowUs
Rsyslog configuration and use tutorial
Building intelligent gray-scale data system from 0 to 1: Taking vivo game center as an example
[AI system frontier dynamics, issue 40] Hinton: my deep learning career and research mind method; Google refutes rumors and gives up tensorflow; The apotheosis framework is officially open source
2022KDD预讲 | 11位一作学者带你提前解锁优秀论文
How real-time cloud interaction helps the development of education industry
Apache服务器访问日志access.log设置
CommVault cooperates with Oracle to provide metallic data management as a service on Oracle cloud