MySQL的Double Write并不难理解

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 今天为大家介绍一个新的名词:double write。相信你还记得,我之前有写笔记跟大家分享过,在MySQL组织数据的基本单位是存在于磁盘上的数据页。数据页被读取到内存(Buffer Pool)中后被称为缓存页。默认情况下每个数据页的大小是16kb,数据页中存储的就是一行行真实的记录,也叫做数据行。

问题引入- 断电了#


今天为大家介绍一个新的名词:double write。


相信你还记得,我之前有写笔记跟大家分享过,在MySQL组织数据的基本单位是存在于磁盘上的数据页。数据页被读取到内存(Buffer Pool)中后被称为缓存页。默认情况下每个数据页的大小是16kb,数据页中存储的就是一行行真实的记录,也叫做数据行。


mysql> SHOW GLOBAL VARIABLES LIKE 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+


当有写操作对Buffer Pool中的数据页做了更新,我们把这种被改变过的数据页叫做:脏页。它是需要被刷新会磁盘的。这时问题就来了,对于计算机硬件或者是操作系统来说,每次原子IO操作的吞吐量量是小于16KB的,一般每个扇区的大小是512字节。


# 文件系统块大小:一般为4k
~]# getconf PAGESIZE
4096
~]# fdisk -l
磁盘 /dev/sda:53.7 GB, 53687091200 字节,104857600 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x000a88ef
 设备 Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     2099199     1048576   83  Linux
/dev/sda2         2099200   104857599    51379200   8e  Linux LVM
磁盘 /dev/mapper/centos-root:50.5 GB, 50457477120 字节,98549760 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘 /dev/mapper/centos-swap:2147 MB, 2147483648 字节,4194304 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节


那这么看来,当你想把一个16K大小的数据页写入到磁盘中时,结果刚写了4k,突然断电机器宕机了。那此时只有一部分是写入成功的。这就是大家常说的: partial page write


不一会 - 来电了#


还是接着上面的描述说,不一会电源正常了,开机重启MYSQL,这时MySQL会进入到崩溃恢复的阶段。


正常的崩溃恢复流程是:

  1. 将数据页从磁盘中读入到内存中
  2. 检查数据页中的LSN标记和redo log中的LSN谁更新,如果相同表示此时的数据页中的数据就是最新的,如果redo log的LSN比数据页中的LSN大,说明数据页中的数据是过时的数据,按redo重做出一份最新数据


但是现在问题是:因为MySQL的Crash是由断电引发的,操作系统都没来得及将数据页完整的写入到磁盘中,导致崩溃恢复的第一步就失败了,因为MySQL会检查出:这个数据页是个不完整的数据页。


想了解更多崩溃恢复的知识,可以看这篇笔记: https://mp.weixin.qq.com/s/6dQnlvjqOo6A0e_h8vST3w


Double write工作流程#


结合double write来看一下一条update sql的执行流程


Step1: 满足update条件的数据页如果不再Buffer Pool中,就进行一次IO操作,将其加载进磁盘。

Step2: 将该数据页修改成脏页。

Step3: 当需要将缓冲池的脏页刷新到 data file 时,并不直接写到数据文件中,而是先拷贝至内存中的 double write buffer。

Step4: 接着从 double write buffer 分两次写入磁盘共享表空间中,每次写入 1MB,并马上调用 fsync 函数,同步到磁盘,避免缓冲带来的问题。

Step5: 完成Step2后,再将两次写缓冲区写入其对应的单独的数据文件。


关于fsync函数可以看我这篇笔记:https://mp.weixin.qq.com/s/tyxd64gGa_SmR6c9vrwf1w


恢复的过程#



  1. 将数据页从磁盘中读入到内存中
  2. 检查到数据页损坏了,尝试通过double write恢复数据。
  3. 如果 double write 的数据是完整的,用 double buffer 的数据页替换坏掉的数据页。


那,如果 double write 中的数据页被写坏了怎么办?

其实没关系,因为是先往共享表空间中写double write数据页,再往各个表对应的表空间文件中写实际的数据页,如果double write中的数据页坏点了,那恰恰说明,各个表对应的表空间文件中的数据页没坏!恢复的流程不会被打断!


配置参数#


# 查看是否启用了double write,以及相关参数
mysql> SHOW VARIABLES LIKE 'innodb_doublewrite%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| innodb_doublewrite            | ON    |
| innodb_doublewrite_batch_size | 120   |
+-------------------------------+-------+
2 rows in set (0.02 sec)
# 查询double write的使用情况
mysql> SHOW STATUS LIKE 'innodb_dblwr_%';
+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Innodb_dblwr_pages_written | 14615 |   #从BP写入到dblwr的page数
| Innodb_dblwr_writes        | 636   |   #写文件的次数
+----------------------------+-------+
2 rows in set (0.02 sec)


疑问#


看到这里你肯定已经知道了double write解决了数据页被写坏的情况,也就是说,redo log不能对一个本身就坏掉的数据页进行重做。


但是,不知道你有没有这样的疑问,那redo log也是以文件的形式存在于磁盘上的,那假如在write redo log时,断电了呢?那redo log不也被损坏了?那还崩溃恢复个锤子?

答:是这样的:事务产生的redo log先被组织成redo log block。并且redo log block其实就在redo log buffer 中。而redo log block的大小==操作系统一次原子IO的吞吐量512字节就像下图这样:



推荐阅读#


  1. MySQL的修仙之路,图文谈谈如何学MySQL、如何进阶!(已发布)
  2. 面前突击!33道数据库高频面试题,你值得拥有!(已发布)
  3. 大家常说的基数是什么?(已发布)
  4. 讲讲什么是慢查!如何监控?如何排查?(已发布)
  5. 对NotNull字段插入Null值有啥现象?(已发布)
  6. 能谈谈 date、datetime、time、timestamp、year的区别吗?(已发布)
  7. 了解数据库的查询缓存和BufferPool吗?谈谈看!(已发布)
  8. 你知道数据库缓冲池中的LRU-List吗?(已发布)
  9. 谈谈数据库缓冲池中的Free-List?(已发布)
  10. 谈谈数据库缓冲池中的Flush-List?(已发布)
  11. 了解脏页刷回磁盘的时机吗?(已发布)
  12. 用十一张图讲清楚,当你CRUD时BufferPool中发生了什么!以及BufferPool的优化!(已发布)
  13. 听说过表空间没?什么是表空间?什么是数据表?(已发布)
  14. 谈谈MySQL的:数据区、数据段、数据页、数据页究竟长什么样?了解数据页分裂吗?谈谈看!(已发布)
  15. 谈谈MySQL的行记录是什么?长啥样?(已发布)
  16. 了解MySQL的行溢出机制吗?(已发布)
  17. 说说fsync这个系统调用吧! (已发布)
  18. 简述undo log、truncate、以及undo log如何帮你回滚事物! (已发布)
  19. 我劝!这位年轻人不讲MVCC,耗子尾汁! (已发布)
  20. MySQL的崩溃恢复到底是怎么回事? (已发布)
  21. MySQL的binlog有啥用?谁写的?在哪里?怎么配置 (已发布)
  22. MySQL的bin log的写入机制 (已发布)
  23. 删库后!除了跑路还能干什么?(已发布)
  24. 自导自演的面试现场,趣学数据库的10种文件(已发布)
  25. 大型面试现场:一条update sql执行都经历什么?(已发布)
  26. 大型翻车现场:如何实现记录存在的话就更新,如果记录不存在的话就插入。(已发布)
  27. 视频+图文串讲:MySQL 行锁、间隙锁、Next-Key-Lock、以及实现记录存在的话就更新,如果记录不存在的话就插入如何保证并发安全(已发布)
  28. 自导自演的面试现场:说说char 和 varchar的区别你了解多少?。(已发布)
  29. 自导自演的面试现场之--你竟然不了解MySQL的组提交?。(已发布)
  30. 全网最清楚的:MySQL的insert buffer和change buffer 串讲(已发布)
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
21天前
|
存储 关系型数据库 MySQL
double ,FLOAT还是double(m,n)--深入解析MySQL数据库中双精度浮点数的使用
本文探讨了在MySQL中使用`float`和`double`时指定精度和刻度的影响。对于`float`,指定精度会影响存储大小:0-23位使用4字节单精度存储,24-53位使用8字节双精度存储。而对于`double`,指定精度和刻度对存储空间没有影响,但可以限制数值的输入范围,提高数据的规范性和业务意义。从性能角度看,`float`和`double`的区别不大,但在存储空间和数据输入方面,指定精度和刻度有助于优化和约束。
|
6月前
|
存储 SQL 数据库
MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
|
存储 关系型数据库 MySQL
【必看】MySQL中float、double、decimal三个浮点数据类型的区别与总结!
你还不知道MySQL中float、double、decimal三个浮点类型的区别吗?快来看看吧!
691 0
【必看】MySQL中float、double、decimal三个浮点数据类型的区别与总结!
|
关系型数据库 MySQL
MySQL中float、double、decimal的区别
MySQL中float、double、decimal的区别
205 0
|
存储 关系型数据库 MySQL
mysql面试题:如何区分FLOAT和DOUBLE?
mysql面试题:如何区分FLOAT和DOUBLE?
144 0
|
13天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
39 3
|
13天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
42 3
|
13天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE 'log_%';`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
54 2
|
26天前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
182 15
|
20天前
|
SQL 关系型数据库 MySQL
数据库数据恢复—Mysql数据库表记录丢失的数据恢复方案
Mysql数据库故障: Mysql数据库表记录丢失。 Mysql数据库故障表现: 1、Mysql数据库表中无任何数据或只有部分数据。 2、客户端无法查询到完整的信息。