天天看点

Raft之WAL并行性

转载请附本文链接:https://blog.csdn.net/maxlovezyy/article/details/103156492

文中思想具有普适性,和Raft无关,提到Raft主要是考虑到目前Raft作为一致性协议的情况比较多,因而就更多的说一下如何和Raft结合。

对于热点一直是难题,虽然有cache层面来缓解热点,但对于一致性要求高的场景还是需要持久化,较难处理热点问题,因为热点有着突发性并且分裂有着滞后性,也没办法通过超细粒度的partition分割做热点切分,一个是因为我们总要在时间和空间复杂度上有所控制(考虑meta体量),一个是有时候也较难预测。另外有些partition不太好切分,在逻辑上可能有着亲缘性,物理上就尽量要做到locality。Partition内并行处理可以提高基础的处理能力以便应对绝大部分情况下的热点burst,下面分析下KV存储模型的并行性。

前面聊了Raft之状态机的并行性,本文聊一聊WAL的并行性。

WAL之所以诞生我理解有两个方面的原因:一个是原子性的需求,由于一条WAL日志是作为一个原子单元(比如通过checksum进行完整性保证),状态机的多个变更可以合并到一个WAL日志条目中实现原子性(中间挂了redo);一个是性能上的考量,无论是HDD还是SSD,顺序写的吞吐都要高于随机写。

基于上面说的,直觉上WAL最简单的设计维护一个WAL文件,一个埃一个紧凑性的写log entry,同时维护一个单调递增的id分配给每一个log entry方便使用,目前主流的存储系统基本都是这样做的。对于KV数据模型,如果不考虑多keys的原子性操作,由于不同keys之间是没有关系的,那么完全可以把不同keys的日志通过hash等方式分散到不同的多个WAL文件之中。对于多keys原子操作的支持,多一个公共的WAL文件只写原子操作,另外所有log entries的index共享一个id generator就能满足了。如果没有多keys原子操作,那就更简单了,所有都分离。

Raft之WAL并行性

当一个状态机所属的WAL并行之后,出现了几个问题:

  • Q:不同WAL log持久化时机不同,redo的时候怎么维护snapshot的index?

    A:为每一个WAL log单独维护一个即可。

  • Q:如何与Raft日志复制结合?

    A:每一个WAL log走单独的复制流。实现上可以复用一个AppendEntries通道,把log entry加一个stream id域即可。

  • Q:如何与Raft选举结合?

    A:核心问题就是对于日志up-to-date的判定由一个对变成了N个对。那么只要满足1. 谁日志文件个数多谁up-to-date 2. 当且仅当所有的日志文件的相比其他对应的文件的都up-to-date。

  • Q:如何与Raft日志连续性原则结合?

    A:Raft的日志连续性其实本质上是逻辑概念上的连续性,即事实上的log entry是否连续了,其index出现gap是不影响逻辑上的连续性的,是无关的,index只要保证单调递增即可,目的是要做到能进行log entry up-to-date的比较。比如对于标准Raft,我生成下一个index的方式由++改为加一个随机数,并不会影响Raft本身。那么问题来了,为什么我们还要在不同的WAL间共享一个id生成器呢?因为common WAL,需要维持顺序一致性。

  • Q:如何与Shared-Storage结合?

    A:直接用就行了,没有Raft那些事了。

  • Q:这样做有一个坏处就是本来可能更连续的WAL IO被拆的更细碎了,如何考虑?

    A:假设压力大,那么不会细碎,因为每一个WAL log都会有batch的能力。假设没压力情况下,突然来N个请求分属不同的log,确实相比走一个log会细碎一点,但本就没压力细碎点又有什么呢。。

  • Q:如何简单理解?

    A:本质就是拆除了多个Raft log层面的逻辑,只不过共享一个状态机。

  • Q:和拆成多个partitions相比意义是什么?

    A:其实和并行状态机apply理由一样,考虑扩展一节开始处提到的内容即可:一切皆trade-off。这里拆不会增加metadata进而对metadata服务造成量压力,也能提高每一个partition基础的抗流量突增和热点能力。

原文:https://blog.csdn.net/maxlovezyy/article/details/103156492

继续阅读