看 MySQL InnoDB 和 BoltDB 如何写磁盘
写磁盘问题
DB 产品,会 WAL 后再写磁盘; WAL 日志又称 redo 日志,用于失败时的恢复操作
似乎挺严谨,但是还是有问题:如果写磁盘的那页还没写完,断电
该页使用 redo 日志文件也无法恢复正确了
看下 MySQL InnoDB 存储引擎、 BoltDB 是如何解决该问题
MySQL InnoDB 存储引擎的两次写
顾名思义,就是写 2 次:
- 从
胀页缓存
(内存)到两次写缓存
(内存) - 先顺序写到
磁盘共享表空间
中(连续存储,顺序写,性能很高) - 再离散写磁盘页(真正落地)
写坏情况恢复:
- 如果 2 步骤写坏,从 1 的
磁盘共享表空间
恢复 - 如果 1 步骤写坏,从 redo 日志恢复
因为实际磁盘页未被写坏,因此总能 redo 正确
BoltDB 双 meta 页切换
BoltDB 当前 meta 页指向磁盘 B+ 树
写操作:
写时拷贝
meta 页到副本 meta 页- 查找复制目标
叶子页
(新),写磁盘 - 对
叶子页
(新)到副本 meta 页的root 间的中间节点页,也重新指向并写磁盘 - 最后切换 meta 页(最后写 meta 页到磁盘)
BoltDB 的实现构思巧妙,相当于新建 1 棵 B+ 树,原子切换 meta 页
需要写的页数 1 页到 N 页不等(数据少,就在 meta 页)
MySQL InnoDB 和 BoltDB 实现对比
- MySQL InnoDB 实现朴实; BoltDB 构思精巧(或者说更大程度是从代码精简角度出发的)
- MySQL InnoDB 写入算法稳定; BoltDB 根据数据量大小,需要写的页数不稳定(更多情况写的页数会大等于 2 次)
redo 日志文件为啥不需要类似两次写机制
前面还提到会先写 redo 日志文件,那么这个文件为啥没有写磁盘问题呢
原因如下:
- redo 日志文件的实现都是追加型(或其变种,如追加型 + 环形),不存在写坏原数据
- 跟严谨的 redo 日志文件写(如 InnoDB),是按磁盘块写,这样算法中某些必须原子的信息,不存在写一半的情况