WAL(Write Ahead Log)预写日志

什么是 WAL

WAL(Write Ahead Log)预写日志,是数据库系统中常见的一种手段,用于保证数据操做的原子性和持久性。mysql

在计算机科学中,预写式日志(Write-ahead logging,缩写 WAL)是关系数据库系统中用于提供原子性和持久性(ACID 属性中的两个)的一系列技术。在使用 WAL 的系统中,全部的修改在提交以前都要先写入 log 文件中。算法

log 文件中一般包括 redo 和 undo 信息。这样作的目的能够经过一个例子来讲明。假设一个程序在执行某些操做的过程当中机器掉电了。在从新启动时,程序可能须要知道当时执行的操做是成功了仍是部分红功或者是失败了。若是使用了 WAL,程序就能够检查 log 文件,并对忽然掉电时计划执行的操做内容跟实际上执行的操做内容进行比较。在这个比较的基础上,程序就能够决定是撤销已作的操做仍是继续完成已作的操做,或者是保持原样。sql

WAL 容许用 in-place 方式更新数据库。另外一种用来实现原子更新的方法是 shadow paging,它并非 in-place 方式。用 in-place 方式作更新的主要优势是减小索引和块列表的修改。ARIES 是 WAL 系列技术经常使用的算法。在文件系统中,WAL 一般称为 journaling。PostgreSQL 也是用 WAL 来提供 point-in-time 恢复和数据库复制特性。数据库

备份

咱们想想,若是想保证对一个数据的操做能够恢复。能够怎么作?你不用去想数据库是怎么实现的,也不用想过高深。其实这是一个很简单的问题,咱们经常在处理这种问题。最简单的方法其实就是备份一份数据:当我须要对一条数据作更新操做前,先将这条数据备份在一个地方,而后去更新,若是更新失败,能够从备份数据中回写回来。这样就能够保证事务的回滚,就能够保证数据操做的原子性了。其实 SQLite 引入 WAL 以前就是经过这种方式来实现原子事务,称之为 rollback journal, rollback journal 机制的原理是:在修改数据库文件中的数据以前,先将修改所在分页中的数据备份在另一个地方,而后才将修改写入到数据库文件中;若是事务失败,则将备份数据拷贝回来,撤销修改;若是事务成功,则删除备份数据,提交修改。c#

WAL

再继续上面的问题?如何作到数据的可恢复(原子性)和提交成功的数据被持久化到磁盘(持久性)?另外一种机制就是WAL,WAL 机制的原理也很简单:修改并不直接写入到数据库文件中,而是写入到另一个称为 WAL 的文件中;若是事务失败,WAL 中的记录会被忽略,撤销修改;若是事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。缓存

WAL 的优势

  1. 读和写能够彻底地并发执行,不会互相阻塞(可是写之间仍然不能并发)。
  2. WAL 在大多数状况下,拥有更好的性能(由于无需每次写入时都要写两个文件)。
  3. 磁盘 I/O 行为更容易被预测。
  4. 使用更少的 fsync()操做,减小系统脆弱的问题。

提高性能

咱们都知道,数据库的最大性能挑战就是磁盘的读写,许多先辈在提供数据存储性能上绞尽脑汁,提出和实验了一套又一套方法。其实全部方案最终总结出来就三种:随机读写改顺序读写缓冲单条读写改批量读写单线程读写改并发读写。WAL 其实也是这两种思路的一种实现,一方面 WAL 中记录事务的更新内容,经过 WAL 将随机的脏页写入变成顺序的日志刷盘,另外一方面,WAL 经过 buffer 的方式改单条磁盘刷入为缓冲批量刷盘,再者从 WAL 数据到最终数据的同步过程当中能够采用并发同步的方式。这样极大提高数据库写入性能,所以,WAL 的写入能力决定了数据库总体性能的上限,尤为是在高并发时。并发

checkpoint

上面讲到,使用 WAL 的数据库系统不会再每新增一条 WAL 日志就将其刷入数据库文件中,通常积累必定的量而后批量写入,一般使用为单位,这是磁盘的写入单位。 同步 WAL 文件和数据库文件的行为被称为 checkpoint(检查点),通常在 WAL 文件积累到必定页数修改的时候;固然,有些系统也能够手动执行 checkpoint。执行 checkpoint 以后,WAL 文件能够被清空,这样能够保证 WAL 文件不会由于太大而性能降低。elasticsearch

有些数据库系统读取请求也可使用 WAL,经过读取 WAL 最新日志就能够获取到数据的最新状态。分布式

具体实现

常见的数据库通常都会用到 WAL 机制,只是不一样的系统说法和实现可能有所差别。mysql、sqlite、postgresql、etcd、hbase、zookeeper、elasticsearch 等等都有本身的实现。高并发

mysql

mysql 的 WAL,你们可能都比较熟悉。mysql 经过 redo、undo 日志实现 WAL。redo log 称为重作日志,每当有操做时,在数据变动以前将操做写入 redo log,这样当发生掉电之类的状况时系统能够在重启后继续操做。undo log 称为撤销日志,当一些变动执行到一半没法完成时,能够根据撤销日志恢复到变动之间的状态。mysql 中用 redo log 来在系统 Crash 重启之类的状况时修复数据(事务的持久性),而 undo log 来保证事务的原子性。

zookeeper

和大多数分布式系统同样,ZooKeeper 也有 WAL(Write-Ahead-Log),对于每个更新操做,ZooKeeper 都会先写 WAL, 而后再对内存中的数据作更新,而后向 Client 通知更新结果。另外,ZooKeeper 还会按期将内存中的目录树进行 Snapshot,落地到磁盘上。这么作的主要目的,一固然是数据的持久化,二是加快重启以后的恢复速度,若是所有经过 Replay WAL 的形式恢复的话,会比较慢。

elasticsearch

若是没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,elasticsearch 不能保证数据在断电甚至是程序正常退出以后依然存在。为了保证可靠性,须要确保数据变化被持久化到磁盘。

在动态更新索引时,elasticsearch 说一次完整的提交会将段刷到磁盘,并写入一个包含全部段列表的提交点。Elasticsearch 在启动或从新打开一个索引的过程当中使用这个提交点来判断哪些段隶属于当前分片。

即便经过每秒刷新(refresh)实现了近实时搜索,elasticsearch 仍然须要常常进行完整提交来确保能从失败中恢复。但在两次提交之间发生变化的文档怎么办?

Elasticsearch 增长了一个 translog ,或者叫事务日志,在每一次对 Elasticsearch 进行操做时均进行了日志记录。

etcd

用过 etcd 的同窗可能会发现,etcd 的数据目录下有两个子目录walsnap。它们的做用就是实现 WAL 机制用的。

wal: 存放预写式日志,最大的做用是记录了整个数据变化的所有历程。在 etcd 中,全部数据的修改在提交前,都要先写入到 WAL 中。

snap: 存放快照数据,etcd 防止 WAL 文件过多而设置的快照,存储 etcd 数据状态。

WAL 机制使得 etcd 具有了如下两个功能:

  • 故障快速恢复: 当你的数据遭到破坏时,就能够经过执行全部 WAL 中记录的修改操做,快速从最原始的数据恢复到数据损坏前的状态。
  • 数据回滚(undo)/重作(redo):由于全部的修改操做都被记录在 WAL 中,须要回滚或重作,只须要方向或正向执行日志中的操做便可

hbase

hbase 实现 WAL 的方法将 HLog,hbase 的 RegionServer 会将数据保存在内存中(MemStore),直到知足必定条件,将其 flush 到磁盘上。这样能够避免建立不少小文件。内存存储是不稳定的,HBase 也是使用 WAL 来解决这个问题:每次更新操做都会写日志,而且写日志和更新操做在一个事务中。

推荐系列

Mysql 大表问题和解决
Mysql 主键问题
列式存储
时间序列数据库(TSDB)初识与选择
十分钟了解 Apache Druid
Apache Druid 底层存储设计
Apache Druid 的集群设计与工做流程

想了解更多数据存储相关知识,请关注个人公众号。

MageByte
相关文章
相关标签/搜索