自导自演的面试现场之--你竟然不了解MySQL的组提交?
Hi,大家好!我是白日梦!本文是MySQL专题的第 26 篇。
下文还是白日梦以自导自演的方式,围绕“组提交”展开本话题。看看你能抗到第几问吧
换一种写作风格,自导自演面试现场!感觉这样还是比较有趣的,欢迎大家订阅我的MySQL专题,公众号首发!持续更新中~
公众号后台回复:数据库 可以参与抽奖活动,3本《MySQL技术内幕-InnoDB存储引擎》
欢迎关注白日梦,公众号首发!持续连载中
库尼奇瓦,同学,听说你上一面表现的还可以,这一面要不咱继续?
嗯,好啊!
好,你了解MySQL的两阶段提交不?说说看
嗯,了解。 简单来说两阶段提交就是将事务提交分成两部分,经过这两步处理后,我们称这个事务被提交了。
嗯,那两个阶段呢?你说说看!
可以看下面这张图:我们当执行commit命令时,会按照如下进行。
第一阶段:写redo log,并标识上prepare。
-- 中间穿插写binlog --
第二阶段:写redo log,完成事务的最终提交。
嗯,那你知不知道为什么事务的提交要分成两个阶段?
嗯,你看上图中的两阶段是redolog-prepare、redolog-commit这两个阶段,然后在这两个阶段中又写了binlog。
这个redolog主要提供的能力是对事务进行rollback、并且redolog是存储引擎层面记录的日志。
而binlog的作用是方面我们进行数据的备份以及MySQL集群主从之间的数据同步使用,并且binlog是MySQL上层,也就是Server层面记录的日志。
综上:MySQL的两阶段提交是为了保证redolog、binlog两者在逻辑上的一致性。才能进一步保证。事务的回滚、数据备份、已经MySQL集群之间的数据才是安全可靠的
嗯,那你能不能举个例子,更直观的告诉我,redolog、binlog两者在逻辑一致的必要性以及用途?
嗯,好啊!,比如这个例子:
在这个例子中,进行完第三步之后,没来得及写binlog,然后主库就挂了,事务也没来得及提交。
这时主库从新启动之后会选择将这个事务丢弃,因为如果它将事务提交了,从库们相对主库来说就少了这条数据,造成了主从数据不一致问题
嗯,在看这个例子
在这个例子中主库宕机前虽然也没有完成对事务对提交,但是它已经写了redolog-prepare、还写了binlog,binlog写完之后很可能从库已经收到这个最新的binlog,并且将这个binlog中的数据回放到自己身上了。
所以主库重新启动之后呢,会选择按照redolog将宕机前的事务状态从内存中恢复出来,也就是说把内存中的缓存页改成脏数据页,然后提交事务
这时主库如果不提交事务,那主库就比从库少了一条数据,同时会造成主从不一致的情况出现。
嗯,你说的没错。我有个问题哈,你看你画的这张图,事务提交时写了好几次日志。
而且一般我们线上的数据库都有这两个配置
# 该参数控制binlog的落盘时机# 设置为1表示当事务被提交时将binlog落盘# 设置为0表示由文件系统自己控制binlog的落盘时机sync_binlog=1# 该参数控制redolog的落盘时机 # 设置为1表示当事务被提交时将redolog落盘innodb_flush_log_at_trx_commit=1
那你有没有想过:即使写日志是磁盘的顺序IO速度极快,即使固态硬盘的性能很🐂,那终究也还是在跟磁盘打交道啊!
那你是否了解MySQL针对这个现状有什么优化的落地实现方案吗?
我提醒你一下,比如:组提交
哦!我还真了解一些group commit的概念!
在MySQL早期的设计中,所谓的组提交,也就是 group commit 实际上提交的是group commit redolog。(而不是binlog)
而且MySQL写redolog并不是产生一条redolog就写一条redo log的!而是以redo log block为单位写入磁盘,而且在redo log block 之上还有个redo log buffer的概念
总结来说就是:写redolog要分成2大步:
Step1:将redolog写入内存buffer中。
Step2:将redolog fsync到磁盘中。
而组提交的概念是说:当进行fsync时,一下子将多个事务日志写入到磁盘中。 通俗来讲,假如说你写一次磁盘需要10ms,如果我们按条每个redolog都写一次磁盘的话,10条redolog就需要100ms的耗时。
现在我们有了组提交,可以一次fsync将10条redolog一次磁盘IO就持久化到磁盘中,耗时可能也就十几ms的样子。性能是有所提升的。
嗯,你说的没错!而且我还注意到了你说的一个细节问题,你上面说,原来的group commit针对的是redolog,而不是binlog。这个缘由你能展开说一下吗?
我.....
好的,这个问题就得从binlog的作用说起了。MySQL不可能无缘无故的就写binlog,它之所以记录binlog是因为它想获取到写binlog带给它的红利。
那什么红利呢?其实前面说了很多遍了,主要的红利就是:binlog给了MySQL搭建集群的可能性,以及数据备份的能力。
而且默认情况下binlog是不会开启的。其实说白了,如果你不需要binlog带给我们的能力,比如你偏偏就不需要做数据的备份、或者搭建集群,那么其实你直接使用默认配置不开启binlog就好了。此时的两阶段提交也不复存在。
但是事实并不是这样的,线上的数据库都是以集群的形式存在、并且也需要数据备份。也就是说binlog是开启的状态。事务的提交也是走的两阶段提交。
那,回到我们组提交的话题来看,其实在早期的MySQL中,并没有一个很好的机制让 组提交和两阶段提交共存的!
嗯,为什么这么说?
嗯,其实你大概一想就知道为什么了。根本原因就在用 binlog是MySQL的上层(Server层)记录的。而redolog是下层的存储引擎层记录的。
所以你突然整一个redolog的组提交出来,那两阶段提交怎么办?你为了性能哐当一下将内存中的redolog全落盘了,但是两阶段提交中每一步写日志的顺序是有要求的呀。它俩正好相违背。
所以其实在InnoDB1.2版本之前,当开启binlog使用两阶段提交时,组提交会失效....
嗯,你说的没错。那后来没有比较好的解决方式呢?
嗯,其实是有的,早在2010年facebook的MySQL技术组,Percona公司就给出了解决方案。后来由MariaDB数据库的开发人员Kristian Nielsen完成了最终的完美解决方案。
所以如果你使用的是MySQL5.6或者更好的版本,它就在两阶段提交的概念上,还加持上了组提交的buff,性能相对之前有了很多的提升。
嗯,那你可否大概说一下如何实现的?
嗯嗯,想了解它的具体的实现可以看这张图:
我稍微解读一下这张图:总体来说分为三个部分,分别是Flush阶段、Sync阶段、Commit阶段
并且它引入了一个新的概念:队列,事务按提交的顺序进入队列中,队列有先进先出的概念,最先进入队列的事务被成为leader
在Flush阶段就是将当前队列中的所有事务的binlog统一写入内存中,Sync就是将当前队列中的所有事务的binlog通过一次fsync统一写入到磁盘中。(相当于批量将binlog落盘)
最后的commit阶段,由队列中的leader根据一定的顺序调用存储引擎层的事务提交,完成两阶段的第二阶段提交。事务结束...
这时就会形成一个比较理想的状态,当一组事务发生Commit时,新的事务可以去Flush。让整个过程中的组提交不断的生效。
嗯,你继续说!
但是如果每次队列中都只有一个事务,那可能会导致性能还不如之前没有这种队列的设计
嗯,你继续往下说。
还有就是我还了解关于组提交相关的一个控制参数
binlog_max_flush_queue_time
这个参数可以控制Flush阶段的等待时间。默认情况下该参数设置为0,推荐设置也为0。
如果我们不把它设置为0,意思就是说想让队列中的事务攒一攒,攒多了再统一处理,想获取到一次fsync将大量日志落盘带来的速度快的红利。但是这样同样会导致事务的响应时间变慢。
嗯!你说的没问题,整体上看你的回答的还可以!
我没有问题了,你还有什么想问我的吗?
没有问题了,感谢大佬百忙抽空来给我面试!
哈哈,客气!好好准备,期待你下一面优秀的表现
推荐阅读
- MySQL的修仙之路,图文谈谈如何学MySQL、如何进阶!(已发布)
- 面前突击!33道数据库高频面试题,你值得拥有!(已发布)
- 大家常说的基数是什么?(已发布)
- 讲讲什么是慢查!如何监控?如何排查?(已发布)
- 对NotNull字段插入Null值有啥现象?(已发布)
- 能谈谈 date、datetime、time、timestamp、year的区别吗?(已发布)
- 了解数据库的查询缓存和BufferPool吗?谈谈看!(已发布)
- 你知道数据库缓冲池中的LRU-List吗?(已发布)
- 谈谈数据库缓冲池中的Free-List?(已发布)
- 谈谈数据库缓冲池中的Flush-List?(已发布)
- 了解脏页刷回磁盘的时机吗?(已发布)
- 用十一张图讲清楚,当你CRUD时BufferPool中发生了什么!以及BufferPool的优化!(已发布)
- 听说过表空间没?什么是表空间?什么是数据表?(已发布)
- 谈谈MySQL的:数据区、数据段、数据页、数据页究竟长什么样?了解数据页分裂吗?谈谈看!(已发布)
- 谈谈MySQL的行记录是什么?长啥样?(已发布)
- 了解MySQL的行溢出机制吗?(已发布)
- 说说fsync这个系统调用吧! (已发布)
- 简述undo log、truncate、以及undo log如何帮你回滚事物! (已发布)
- 我劝!这位年轻人不讲MVCC,耗子尾汁! (已发布)
- MySQL的崩溃恢复到底是怎么回事? (已发布)
- MySQL的binlog有啥用?谁写的?在哪里?怎么配置 (已发布)
- MySQL的bin log的写入机制 (已发布)
- 删库后!除了跑路还能干什么?(已发布)
- 自导自演的面试现场,趣学数据库的10种文件(已发布)
- 大型面试现场:一条update sql执行都经历什么?(已发布)
- 大型翻车现场:如何实现记录存在的话就更新,如果记录不存在的话就插入。(已发布)
最后,欢迎关注白日梦的公号哦~
换一种写作风格,自导自演面试现场!感觉这样还是比较有趣的,欢迎大家订阅我的MySQL专题,公众号首发!持续更新中~