绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
分布式思考:我们需要WAL吗?
2022-04-15 18:49:32

## 前言

历史上看,是先有单机系统,然后再向分布式演变。我们很多分布式的设计,都源自单机的很多经验。这是没错的,因为分布式本来就是众多单机参与的一个集群系统。我们当然要借鉴单机的经验和单机的基础。

但是,分布式源自单机,但不能思想受限于单机。

我的观点:分布式要学习和复用单机的知识,但在一些领域,要勇敢跳出单机的思维限制。

再看一个思考:我们需要WAL吗?

## 单机为什么需要WAL?

WAL,write ahead log,是为了优化磁盘性能的一个方法,广泛用于数据库系统(你几乎找不到不支持WAL的数据库系统)

磁盘是慢速的,但磁盘的慢速,不是简单的一个点,而是有很复杂的机理。

大家可以参考我之前的一个文章:

Throughput, Bandwidth, Latency

里面有一个磁盘在不同Pattern下的测试数据,可以看到,对于不同的block size,磁盘的Throughput有几十倍的差别。

同时,磁盘还有一个写放大问题,比如:如果我们通过B+树在内存保存数据,如果将某个修改的内存Page即使刷盘的话,会有很大倍数的写放大,很不经济。

大家可以参考另外一篇文章

Kafka is Database,里面有对MySQL redo的分析:用Log写盘,来替代直接内存Page写盘,所带来的好处。

简而言之,就是利用磁盘对于Log效率高的特性,让数据的修改,分在两次(即冗余),一次在WAL,并很快落盘;一次在你真正dataset(如B+树的内存页),晚些落盘,从而提高整个系统的Throughput。这样,万一发生灾难,你可以用WAL挽救你的数据。

WAL还有另外一个作用,就是ACID中A的保证。因为data page并不能保证Atomic(数据库可能分开写盘、也可能部分Partial写盘)。

于是,你可以看到,在很多数据库系统里,WAL是无处不在,比如:MySQL的redo log,RocksDB的WAL,etcd的WAL。都是这个思想。

## 分布式下还需要WAL吗?

首先,你从上面的分析可以看出,WAL是冗余的。数据被写了两次。

如果理论上不存在灾难,我们完全可以不用WAL。

请你再参考我之前的一个分析:

分布式下:我们还需要fsync吗?

你会发现,对于WAL,我们可以用同样的思路。因为:

1. 数据已经在内存的data structure里存在多份(多机),我们可以满足用户不丢数据的承诺(只要两台机器不同时死,而且我们认为两台同时死的概率趋近于零)

2. 我们不用急着对内存的data structure刷盘,从而一样获得上面用WAL的那些好处:数据页可以多次修改但一次刷牌,数据如果连续可以做类似Log式的刷盘(比如LSM下的SST就是数据连续的)

所以,我的倾向,在分布式系统里,我们可以去除WAL。

## 一个这样实践的案例BunnyRedis(还有Kafka)

BunnyRedis,就是省掉了WAL。虽然它的磁盘存储用了RocksDB,但RocksDB有开关可以关闭WAL,而BunnyRedis的代码是不写WAL的。

你可能会问,BunnyRedis不是用到了Kafka,那个Kafka Log不就是BunnyRedis的WAL吗?

是的,Kafka的Log,相当于BunnyRedis的WAL。但是,这个WAL并不是常规数据库里的那个意义的WAL。

因为:

1. 理论上,我可以关闭Kafka的写盘,只要至少一台bunny-redis进程活着,就会有一个dataset被bunny-redis进程所拥有。

2. Kafka收到bunny-redis的数据,它并不很快落盘。WAL对于很多数据库系统是至少每秒必须落盘一次(至多丢1秒或2秒的数据),但对于Kafka,完全依赖操作系统的后台刷盘,时间可以到几十分钟。也就是说,Kafka Log, 作为BunnyRedis的WAL,它不在磁盘上,而在内存上。

3. 而且BunnyRedis这个所谓的WAL不会丢数据,只要一台Kafka broker还活着。

对于Kafka而言,它的数据,就是它的Log(所以,Kafka没有WAL)。

而且,Kafka依赖操作系统后台写入磁盘的速度,几乎等同于一般网络的Throughput,这个没有任何瓶颈。

详细可Kafka官方说明:Don't fear the filesystem!

附: 关于下面的讨论

本文下面的评论区有很多好意见,也非常感谢大家的宝贵思想。但涉及一个容易让大家谈的目标不是同一个东西的问题,就是LOG和WAL的区分。由于评论区比较短小,所以,我写了一个文章来阐述我的理解,请参考:

Tony:作为数据的Log和WAL的本质区分8 赞同 · 1 评论文章


## 补:关系型数据库事务Transaction对于WAL的影响

知乎网友提供了很多好想法,非常感谢。其中一个提到:WAL在关系型数据库中,有事务的功能,即要保证Atomic,要保证rollback。

大家如果看这个文章,其核心思想是:

在分布式下,放弃单机的灾难恢复约束下的持久化要求,对于重复信息入盘可以不再考虑,因为集群另外一台机器可以弥补

这个想法里有两个关键点:

1. 用于灾难恢复(crash recover)

2. 用于重复信息(duplicated data or copy)

在关系型数据库中,比如MySQL,其WAL除了灾难恢复外,还有事务Transaction的功能,要求Atomic保证,即All or Nothing,如果发生意外,可以rollback。

如果进一步分类,包含两个,一个是redo,一个是undo。

对于redo,我们完全可以按照这个文中的想法,不用入盘。因为,它符合上面两个关键点,用于灾难,而且重复,即它本质是冗余的。

但是对于undo,我们不能这样做。因为undo并不完全是为crash灾难准备的,作为日常事务,我们可以在SQL语句中间,主动进行rollback。而且,它也不完全是一个copy(比如:MySQL里undo信息有时存的是SQL语句,而不是data)。

但是,对于undo里面用于crash recover的部分,我们同样可以考虑不入盘,因为它符合上面两个关键点。我对undo在MySQL里的细节不熟悉,但我知道undo信息存在两个地方,其中一部分就在WAL中(包含在redo文件里)。

所以,核心本质在于:

1. 分布式条件下,将冗余的入盘拿掉,因为设定环境发生了改变,不是单机

2. 尽可能减少磁盘操作这个大的cost(也就是减少持久化的约束),让事务过程大部分都发生在内存上

这样做了,我们还是能保证关系数据库的事务功能

分享好友

分享这个小栈给你的朋友们,一起进步吧。

分布式思考和实践
创建时间:2022-04-14 14:15:30
关于分布式在数据库领域的应用的一些思考以及一些程序应用的开发
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • szstonelee
    栈主

小栈成员

查看更多
  • miemieMIA
  • LCR_
  • jinchuan
  • MrSun
戳我,来吐槽~