博客
关于我
自导自演的面试现场之--你竟然不了解MySQL的组提交?
阅读量:404 次
发布时间:2019-03-06

本文共 3590 字,大约阅读时间需要 11 分钟。

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专题,公众号首发!持续更新中~

转载地址:http://ajikz.baihongyu.com/

你可能感兴趣的文章
python-day3 for语句完整使用
查看>>
ButterKnife使用问题
查看>>
为什么讨厌所谓仿生AI的说法
查看>>
ORACLE 客户端工具
查看>>
基于LabVIEW的入门指南
查看>>
weblogic之cve-2015-4852
查看>>
Java注释
查看>>
C++ 函数重载
查看>>
.NET微信网页开发之使用微信JS-SDK调用微信扫一扫功能
查看>>
使用mybatis-generator生成底层
查看>>
Mybatis【5】-- Mybatis多种增删改查那些你会了么?
查看>>
计算输入的一句英文语句中单词数
查看>>
lvs+keepalive构建高可用集群
查看>>
6 个 Linux 运维典型问题
查看>>
Failed to get D-Bus connection: Operation not permitted解决
查看>>
取消vim打开文件全是黄色方法
查看>>
一个系统部署多个tomcat实例
查看>>
HP服务器设置iLO
查看>>
从头实现一个WPF条形图
查看>>
使用QT实现一个简单的登陆对话框(纯代码实现C++)
查看>>