天增的博客
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
  • posts
  • RedoLog诞生史
2022-07-22

RedoLog诞生史

# RedoLog诞生史

InnoDB存储引擎是通过页为单位对数据进行访问,换句话说对数据库的所有操作都最终会作用到这个页上面。

但是,磁盘的运行速度远远慢于内存,所以在对这个页操作的时候需要将数据给整到内存中去,来加快增删改查的速度。

MySQL的设计者设计了了一个叫做Buffer Pool的存储在内存中的数据结构,用于平衡存储介质和内存之间的速度差异:

  • 写入时先写入Buffer Pool中,后刷到磁盘中

  • 读取时

    • Buffer Pool中有完整数据,则直接返回
    • Buffer Pool中只记录了更改状态,则需要合并磁盘和Buffer Pool
    • Buffer Pool中无数据,进入磁盘查找

但是,在这种情况下不错处理会有一个问题,在写入Buffer Pool成功,但是刷写磁盘时可能由于断电导致没有刷成功,数据出现了丢失。

需要一个新的数据结构,在事务提交完成之前把事务所修改的页面都刷到磁盘中,但是这个简单粗暴的做法有些问题:

  1. 刷新一个完整的数据页太浪费了

    InnoDB中是以页为单位来进行磁盘IO,事务提交时需要将一个完整的页面从内存中刷新到磁盘。一个页面默认是16KB大小,只修改一个字节就要刷新16KB的数据到磁盘上显然是太浪费了。这种在存储系统中有个专有的名词 —— 写放大(Write Amplification)

  2. 随机IO刷起来比较慢

    一个事务可能包含很多语句,即使是一条语句也可能修改许多页面,事务修改的这些页面在物理磁盘上不相邻,每一次操作前都需要寻址,称之为随机IO

针对这两种方式也比较好解决:

  1. 刷新完成数据页浪费

    那就记录被修改的位置,把修改了哪些东西记录一下就好,比如:

    update test set a = 2;

    将第0号表空间的100号页面的偏移量为1000处的值更新为2。

  2. 随机IO刷起来比较慢

    这个就更好解决了,把随机IO给弄成顺序IO,磁盘中开辟一块单独的连续空间,就直接写这片空间就好了。

    那空间写满了怎么办?重写!

    空间开辟: 0....100

    写到100之后,重新从0开始写。只需要做个标记,如果写入的,已经被实实在在的刷到磁盘中了,则这块是可以重写的;否则,MySQL整体阻塞,免得数据出现异常

有了这些手段,即使MySQL重启崩溃了,也仅仅需要从这个顺序空间中将数据的操作给捞出来,进行回放重新更新一下数据页就好了。

这个手段,MySQL中已经有了,叫做redo log

  • redo日志占用的空间非常小
    存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间是很小。
  • redo日志是顺序写入磁盘的
    在执行事务的过程中,每执行一条语句,就可能产生若干条redo日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序IO。

‍

最近更新
01
以 root 身份启动 transmission-daemon
12-13
02
Debian系统安装qbittorrent-nox
12-09
03
LXC Debain12安装zerotier并实现局域网自动nat转发
07-29
更多文章>
Theme by Vdoing | Copyright © 2015-2024 天增 | 苏ICP备16037388号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式