共计 2534 个字符,预计需要花费 7 分钟才能阅读完成。
本篇文章为大家展示了我很理解 MySQL 中的 double write,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
MySQL 里的 double write 是 InnoDB 的三大闪亮特性,另外两个是 insert buffer
和自适应哈希,其实还有几个比如异步 IO,Flush neighbour
Page(刷新邻接页),这个和系统层面的关联性较高,所以三大亮点还是更有针对性的。
当然一说到 MySQL 里的 double write, 其实主要是要应对一个很自然的问题,那就是 partial write。
经典的 partial write 问题
这个问题比较经典,很多数据库设计中都需要考虑到这样一个临界点的问题,MySQL 中的页是 16k, 数据的校验是按照这个为单位进行的,而操作系统层面的数据单位肯定达不到 16k, 比如是 4k, 那么一旦发生断电的时候,只保留了部分写入,如果是 Oracle
DBA 一般对此都会很淡定,说用 redo 来恢复嘛,但是可能我们被屏蔽了一些细节,MySQL 在恢复的过程中一个基准是检查 page 的 checksum,也就是 page 的最后事务号,发生这种 partial
page write 的问题时,因为 page 已经损坏,所以就无法定位到 page 中的事务号,所以这个时候 redo 就无法直接恢复。
由此引申一点,partial write 的问题在 Oracle 中肯定也会存在,但是只是 Oracle 替我们把这个过程平滑的做好了。其中有设计的差异,还有恢复技术的差别。但是无论如何这个问题都不会绕过去,还得解决。
所以这一类问题,如果讨论起来,那可以讨论很长时间,可以把体系结构里的方方面面拿出来分析,做对比。
简单分析 double write 问题
对此我画了一个相对简陋的图,也欢迎大家提出改进建议。
总体来说,double write
buffer 就是一种缓冲缓存技术,主要的设计就是为了防止数据在断电,异常情况下丢失数据。里面有几个点需要注意的就是,数据在 buffer
pool 中修改后成了脏页,这个过程会产生 binglog 记录和 redo 记录,当然数据写入数据文件是一个异步的工作,如果细看,在共享表空间(system
tablespace)中会存在一个 2M 的空间,分为 2 个单元,一共 128 个页,其中 120 个用于批量刷脏数据,另外 8 个用于 Single Page
Flush。根据阿里同学的分析主要是做区分是因为批量刷脏是后台线程做的,这样不影响前台线程。而 Single page
flush 是用户线程发起的,需要尽快的刷脏并替换出一个空闲页出来。所以不是一个严格的 64+64 的拆分。
而数据刷新的过程,是先使用 memcopy 把脏数据复制到内存中的 double write
buffer, 分两次写完,每次写 1MB 到共享表空间,然后就是调用 fsync 来同步到磁盘。这里有一点需要注意的是,这个刷新到共享表空间的过程,虽然是两次,但是是顺序写,所以开销不会很大,也就不会像大家想象的 double
write 性能可能很差,根据 Percona 的测试,大概也就是 5% 左右的差别,数据重要还是性能更重要,这是一个基本的命题。当然后续会再写入对应的表空间文件中,这个过程就是随机写,性能开销就会大一些。所以在早些时候是用 SSD 的时候很多人也会带有如此的顾虑,顺序写还是随机写。
当然 double write 这么设计就是全面为了作为恢复而用,要不这么大张旗鼓就不值得了。这个图来源于 http://blog.csdn.net/renfengjun/article/details/41541809
我觉得已经说得很明白了,就直接引用过来了。
可以看到里面的一个中心词就是 checksum, 如果出现了 partil
write 的时候,比如断电,那么两次写的过程中,很可能 page 是不一致的,这样 checksum 校验就很可能出现问题,而出现问题的时候,因为有了前期写入共享表空间的页信息,所以就可以重构出页的信息重新写入。
double write 的另外一个作用
double write 其实还有一个特点,就是将数据从 double write buffer 写到真正的 segment 中的时候, 系统会自动合并连接空间刷新的方式, 这样一来每次就可以刷新多个 pages,提高效率。
比如下面的环境,我们可以根据 show status 的结果来得到一个基本的合并页的情况。
show status like %dbl%
| Variable_name | Value |
| Innodb_dblwr_pages_written | 23196544 |
| Innodb_dblwr_writes | 4639373 |
通过 InnoDB_dblwr_pages_written/InnoDB_dblwr_writes 就可以得到,通过指标也可基本看明白。
Percona 中的 double write 改进
当然对于 double write,在 Percona 中也在持续改进,在 Percona 5.7 版本中做了一个改进,你可以看到一个新的参数,innodb_parallel_doublewrite_path
| innodb_parallel_doublewrite_path | xb_doublewrite | 在系统层面,也会存在一个 30 的一个文件对应。
-rw-r—– 1 mysql mysql 31457280 Mar 28 17:54 xb_doublewrite 也就是并行 double
write, 关于这个特性的详细描述和测试,可以参考。https://www.percona.com/blog/2016/05/09/percona-server-5-7-parallel-doublewrite/?utm_source=tuicool utm_medium=referral
里面提供了很多详细测试的对比和分析。当然 MariaDB,Facebook,Aurora 也有一些自己的实现方式和考虑,这个限于精力,还没有细细测试分析。
上述内容就是我很理解 MySQL 中的 double write,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注丸趣 TV 行业资讯频道。