Innodb关键特性之什么是doublewrite

56次阅读
没有评论

共计 4077 个字符,预计需要花费 11 分钟才能阅读完成。

本篇内容介绍了“Innodb 关键特性之什么是 doublewrite”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、经典 Partial page write 问题

        介绍 double write 之前我们有必要了解 partial page write(部分页失效)问题。

       InnoDB 的 Page Size 一般是 16KB,其数据校验也是针对这 16KB 来计算的,将数据写入到磁盘是以 Page 为单位进行操作的。我们知道,由于文件系统对一次大数据页(例如 InnoDB 的 16KB)大多数情况下不是原子操作,这意味着如果服务器宕机了,可能只做了部分写入。16K 的数据,写入 4K 时,发生了系统断电 /os crash,只有一部分写是成功的,这种情况下就是 partial page write 问题。

        有经验的 DBA 可能会想到,如果发生写失效,MySQL 可以根据 redo log 进行恢复。这是一个办法,但是必须清楚地认识到,redo log 中记录的是对页的物理修改,如偏移量 800,写’aaaa’记录。如果这个页本身已经发生了损坏,再对其进行重做是没有意义的。MySQL 在恢复的过程中检查 page 的 checksum,checksum 就是检查 page 的最后事务号,发生 partial page write 问题时,page 已经损坏,找不到该 page 中的事务号。在 InnoDB 看来,这样的数据页是无法通过 checksum 验证的,就无法恢复。即时我们强制让其通过验证,也无法从崩溃中恢复,因为当前 InnoDB 存在的一些日志类型,有些是逻辑操作,并不能做到幂等。

        为了解决这个问题,InnoDB 实现了 double write buffer,简单来说,就是在写数据页之前,先把这个数据页写到一块独立的物理文件位置(ibdata),然后再写到数据页。这样在宕机重启时,如果出现数据页损坏,那么在应用 redo log 之前,需要通过该页的副本来还原该页,然后再进行 redo log 重做,这就是 double write。double write 技术带给 innodb 存储引擎的是数据页的可靠性,下面对 doublewrite 技术进行解析,让大家充分理解 double write 是如何做到保障数据页的可靠性。

二、double write 体系结构及工作流程

       double write 由两部分组成,一部分是 InnoDB 内存中的 double write buffer,大小为 2M,另一部分是物理磁盘上 ibdata 系统表空间中大小为 2MB,共 128 个连续的 Page,既 2 个分区。其中 120 个用于批量写脏,另外 8 个用于 Single Page Flush。做区分的原因是批量刷脏是后台线程做的,不影响前台线程。而 Single page flush 是用户线程发起的,需要尽快的刷脏并替换出一个空闲页出来。

        对于批量刷脏,每次找到一个可做 flush 的 page,对其持有 S lock,然后将该 page 拷贝到 dblwr 中,当 dblwr 满后者一次批量刷脏结束时,将 dblwr 中的 page 全部刷到 ibdata 中,注意这是同步写操作;然后再唤醒后台 IO 线程去写数据页。当后台 IO 线程完成写操作后,会去更新 dblwr 中的计数以腾出空间,释放 block 上的 S 锁,完成写入。

        对于 Single Page Flush,则做的是同步写操作,在挑出一个可以刷脏的 page 后,先加入到 dblwr 中,刷到 ibdata,然后写到用户表空间,完成后,会对该用户表空间做一次 fsync 操作。

       Single Page Flush 在 buffer pool 中 free page 不够时触发,通常由前台线程发起,由于每次 single page flush 都会导致一次 fsync 操作,在大并发负载下,如果大量线程去做 flush,很显然会产生严重的性能下降。Percona 在 5.6 版本中做了优化,可以选择由后台线程 lru manager 来做预刷,避免用户线程陷入其中。

        如果发生了极端情况(断电),InnoDB 再次启动后,发现了一个 Page 数据已经损坏,那么此时就可以从 double write buffer 中进行数据恢复了。

double write 工作流程如下:

        当一系列机制(main 函数触发、checkpoint 等)触发数据缓冲池中的脏页进行刷新到 data file 的时候,并不直接写磁盘,而是会通过 memcpy 函数将脏页先复制到内存中的 double write buffer,之后通过 double write buffer 再分两次、每次 1MB 顺序写入共享表空间的物理磁盘上。然后马上调用 fsync 函数,同步脏页进磁盘上。由于在这个过程中,double write 页的存储时连续的,因此写入磁盘为顺序写,性能很高;完成 double write 后,再将脏页写入实际的各个表空间文件,这时写入就是离散的了。各模块协作情况如下图(第一步应为脏页产生的 redo 记录 log buffer,然后 log buffer 写入 redo log file,为简化次要步骤直接连线表示):

查看 doublewrite 工作情况,可以执行命令:

mysql show status like  %InnoDB_dblwr% 
+----------------------------+-----------------+
| Variable_name | Value |
+----------------------------+-----------------+
| Innodb_dblwr_pages_written | 216261751 |
| Innodb_dblwr_writes | 43307580 |
+----------------------------+-----------------+

        以上数据显示,double write 一共写了  61932183 个页,一共写了 15237891 次,从这组数据我们可以分析,之前讲过在开启 double write 后,每次脏页刷新必须要先写 double write,而 double write 存在于磁盘上的是两个连续的区,每个区由连续的页组成,一般情况下一个区最多有 64 个页,所以一次 IO 写入应该可以最多写 64 个页。而根据以上我这个系统 Innodb_dblwr_pages_written 与 Innodb_dblwr_writes 的比例来看,一次大概在 4 个页左右,远远还没到 64,所以从这个角度也可以看出,系统写入压力并不高。

        如果操作系统在将页写入磁盘的过程中发送了崩溃,在恢复过程中,InnoDB 存储引擎可以从工序表空间中的 double write 中找到该页的副本,将其复制到表空间文件,再应用 redo log。下面显示了一个由 double write 进行恢复的过程:

090924 11:36:32 mysqld restarted

090924 11:26:33 InnoDB: Database was not shut down normally!

InnoDB: Starting crash recovery.

InnoDB: Reading tablespace information from the .ibd files…

InnoDB: Crash recovery may have faild for some .ibd files!

InnoDB: Restoring possible half-written data pages from the doublewrite.

InnoDB: buffer…

三、double write 的缺点

       dblwr 位于共享表空间上的 double write buffer 实际上也是一个文件,引入了一次额外写的开销,每个数据页都被要求写两次。由于需要大量的 fsync 操作,所以它会降低 MySQL 的整体性能,但是并不会降低到原来的 50%。这主要是因为:

1) double write 是一个连接的存储空间,所以硬盘在写数据的时候是顺序写,而不是随机写,这样性能更高。

2) 将数据从 double write buffer 写到真正的 segment 中的时候,系统会自动合并连接空间刷新的方式,每次可以刷新多个 pages。

        double write 默认开启,参数 skip_innodb_doublewrite 虽然可以禁止使用 double write 功能,但还是强烈建议大家使用 double write。避免部分写失效问题,当然,如果你的数据表空间放在本身就提供了部分写失效防范机制的文件系统上,如 ZFS/FusionIO/DirectFS 文件系统,在这种情况下,就可以不开启 doublewrite 了

四、double write 在恢复的时候是如何工作的

        如果是写 double write buffer 本身失败,那么这些数据不会被写到磁盘,InnoDB 此时会从磁盘载入原始的数据,然后通过 InnoDB 的事务日志来计算出正确的数据,重新写入到 double write buffer。

        如果 double write buffer 写成功的话,但是写磁盘失败,InnoDB 就不用通过事务日志来计算了,而是直接用 buffer 的数据再写一遍。如上图中显示,在恢复的时候,InnoDB 直接比较页面的 checksum,如果不对的话,Innodb 存储引擎可以从共享表空间的 double write 中找到该页的一个最近的副本,将其复制到表空间文件,再应用 redo log,就完成了恢复过程。因为有副本所以也不担心表空间中数据页是否损坏,但 InnoDB 的恢复通常需要较长的时间。

“Innodb 关键特性之什么是 doublewrite”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-27发表,共计4077字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)