什么是WAL?
在写完上一篇《Pull or Push》之后,原本计划这一片写《存储层设计》,但是临时改变主意了,想先写一篇介绍一下消息中间件最最基础也是最核心的部分:write-ahead logging(WAL)。
什么是WAL
"In computer science, write-ahead logging (WAL) is a family of techniques for providing atomicity and durability (two of the ACID properties) in database systems."——维基百科
在计算机领域,WAL(Write-ahead logging,预写式日志)是数据库系统提供原子性和持久化的一系列技术。
在使用WAL的系统中,所有的修改都先被写入到日志中,然后再被应用到系统状态中。通常包含redo和undo两部分信息。
为什么需要使用WAL,然后包含redo和undo信息呢?举个例子,如果一个系统直接将变更应用到系统状态中,那么在机器掉电重启之后系统需要知道操作是成功了,还是只有部分成功或者是失败了(为了恢复状态)。如果使用了WAL,那么在重启之后系统可以通过比较日志和系统状态来决定是继续完成操作还是撤销操作。
redo log
redo log称为重做日志,每当有操作时,在数据变更之前将操作写入redo log,这样当发生掉电之类的情况时系统可以在重启后继续操作。
undo log
undo log称为撤销日志,当一些变更执行到一半无法完成时,可以根据撤销日志恢复到变更之间的状态。
MySQL中用redo log来在系统Crash重启之类的情况时修复数据(事务的持久性),而undo log来保证事务的原子性。
WAL在消息中间件中的应用
WAL可以说是消息中间件的基础,也是所有存储类系统的基础。
在消息中间件中,WAL没有MySQL中那么复杂,我们只需要记redo log。消息直接存储在redo log中,只要写redo log完成了,那么消息就写入完成了:
消息写入redo log就表明持久化了
且不会出现原子性的问题,消息写入即成功,没写入即失败
存储结构
使用WAL存储数据,就需要去组织存储文件,比如MySQL的binlog文件。在消息中间件中也需要类似的形式去组织redo log,即消息的存储文件。
我们采用固定大小的存储文件,这样在索引消息的时候,只要知道偏移量,就能找到对应的存储文件。比如下面是文件大小为1024的存储文件示例:
消息被不断的追加到最新的存储文件中。
消息在文件中的存储格式大致如上:
采用二进制的格式存储消息
消息是不定长的
所以这里会需要一个结构来索引消息。索引到一条完整的消息只需要两个元素:偏移量、大小。只要有这两个元素就可以从存储日志中读取一段完整的数据(一条完整的消息)。
以上的结构是最简单的消息中间件存储的模型,虽然离真正应用到实践中还有一些距离,但是核心思想是一致的。
考虑这几个问题:
消息具体的存储协议,即存储文件中消息需要包含哪些内容
如何优化索引结构,支持消息回溯、消息过滤等功能
确定一下这几个问题的解决方案基本就是一个可以使用的消息中间件的WAL了。
Crash Recovery
上文说了redo log用于在系统Crash之后做恢复(在中间件中也直接作为数据存储),那么redo log具体我们可以如何使用它进行系统状态的恢复呢?
在消息写入的过程中,这里的状态只有一个,就是消息索引。只要消息索引构建了,那么消息就可以被消息;如果消息索引没构建,那么这条消息就是不可消费的(等价于消息没有写入)。
那么这里的恢复就是在系统Crash之后如何构建索引。
比如上图的状态是已经构建了消息0-3的索引,需要构建消息4-7的索引信息。
这个实现很简单:
消息一旦构建了索引,就记录checkpoint;checkpoint可以定期刷盘
系统恢复过程中读取checkpoint之后的消息构建索引;如果读取的消息不完整,则丢弃消息(可以采用CRC验证之类的方式来校验消息是否完成)
因为消息没有完整写入redo log的情况(写入时系统Crash了)系统并不会响应Producer消息发送成功(只有成功刷盘了才会响应成功),所以直接丢弃不完整的消息并不会对系统语义产生影响(不完整的消息没有响应Producer,也没有构建索引)。
结语
上文介绍了一下WAL,简要的描述了消息中间件存储模型和Crash Recovery,还有一些遗留的问题:
如何实现消息回溯和过滤,如何支持多tag过滤?
消息需要写文件且刷盘,如何保证写入性能?
消费时需要从文件读取消息,如何保证性能?
序列化的消息需要包含哪些属性才能完整的恢复出索引?
往期文章:
什么是WAL?的更多相关文章
- HBase的Write Ahead Log (WAL) —— 整体架构、线程模型
解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...
- HBase的Write Ahead Log (WAL) —— API与基本概念
HBase的数据写入操作,会先记录到HLog中,再真正写入到MemStore中.前者是对写入友好的格式,后者是对查询友好的格式.所以前者吞吐量更高,写入成功率大,提高了系统的可靠性,“基本”可以实现宕 ...
- sqlite之WAL模式
链接 概述 在3.7.0以后,WAL(Write-Ahead Log)模式可以使用,是另一种实现事务原子性的方法. WAL的优点 在大多数情况下更快 并行性更高.因为读操作和写操作可以并行. 文件IO ...
- Sqlite学习笔记(三)&&WAL性能测试
WAL是SQLite3.7.0版本引入的一个重大改进.SQLite官网宣称在很多使用场景下,WAL模型的性能都要好于默认的DELETE模式.下面将针对几个主要场景对WAL性能做测试,测试的硬件与xxx ...
- 预写式日志(Write-Ahead Logging (WAL))
SQL Server中使用了WAL(Write-Ahead Logging)技术来保证事务日志的ACID特性.而且大大减少了IO操作. WAL的核心思想是:在数据写入到数据库之前,先写入到日志.再将日 ...
- InnoDB的WAL方式学习
之前写过一篇博文,<不好的MySQL过程编写习惯>(http://www.cnblogs.com/wingsless/p/5041838.html).这篇博文里强调了不要循环的提交事务,尽 ...
- SQLite的WAL机制
标注:本文部分有黏贴这里的资料,另外还加了一些自己的笔记 使用CoreData或者SQLite3的时候,我们创建的数据库, 在存储的文件夹中有三个文件:分别为:**.sqlite **.sqlite ...
- Hbase的WAL在RegionServer基本调用过程
版权声明:本文由熊训德原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/221 来源:腾云阁 https://www.qclo ...
- Hbase WAL线程模型源码分析
版权声明:本文由熊训德原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/257 来源:腾云阁 https://www.qclo ...
- WAL
WAL record format typedef struct XLogRecord{pg_crc32 xl_crc; /* CRC for this record */XLogRe ...
随机推荐
- 【SSM之旅】Spring+SpringMVC+MyBatis+Bootstrap整合基础篇(一)项目简介及技术选型相关介绍
试水 一直想去搭建个自己的个人博客,苦于自己的技术有限,然后也个人也比较懒散.想动而不能动,想动而懒得动,就这么一直拖到了现在.总觉得应该把这几年来的所学总结一番,这样才能有所成长. 不知在何时,那就 ...
- nginx反向代理node.js获取客户端IP
使用Nginx做node.js程序的反向代理,会有这么一个问题:在程序中获取的客户端IP永远是127.0.0.1 如果想要拿到真实的客户端IP改怎么办呢? 一.首先配置Nginx的反向代理 proxy ...
- PHP核心技术
一.PHP核心技术 1.写出一个能创建多级目录的PHP函数(新浪网技术部) <?php /** * 创建多级目录 * @param $path string 要创建的目录 * @param $m ...
- YII2连表分页
控制器(controller)页面 use \yii\data\Pagination; //引入这个类 public function actionList(){ $data = Clock::fin ...
- WinForm程序,实现只启动一个实例
前言:在我们做的软件中,当点击图标运行时,正常的需求是只需要启动一个软件的实例,这是非常重要的一点,不然就显得我们的软件非常的山寨,笔者在工作中经常遇到同事没有注意这一点,看是不重要,实则非常的重要, ...
- COM组件转换为.NET元数据2
上一篇通过命令的方式实现COM组件与.NET元素的转换.这次直接在VS中转换. 以下为步骤:
- extr_shopping
__author__ = 'ZZG' # noinspection PyCallingNonCallable shopping_list =[ ("iphone",5300), ( ...
- java学习笔记之StringBuilder
StringBuilder总结 StringBuilder概述: StringBuilder是一个线程不安全的类,他在字符串连接方面性能尤其出色 StringBuilder类的构造方法: 1.空参数构 ...
- Solr集群搭建详细教程(一)
一.Solr集群的系统架构 注:欢迎大家转载,非商业用途请在醒目位置注明本文链接和作者名dijia478,商业用途请联系本人dijia478@163.com. SolrCloud(solr 云)是So ...
- HDU 4911 Inversion 树状数组求逆序数对
显然每次交换都能降低1 所以求出逆序数对数,然后-=k就好了.. . _(:зゝ∠)_ #include<stdio.h> #include<string.h> #includ ...