Merkel Tree与反熵修复(Anti-entropy repair)

最近在阅读分布式系统的书籍,看到Cassandra、Dynamo等数据库都有使用Merkel Tree进行反熵修复的内容,但书中并没有具体介绍反熵修复的概念,只是说明了其应用:

  • Dynamo:检验数据是否同步,在弱一致性的分布式系统中实现最终一致性。
  • Cassandra:比较所有副本的数据,将陈旧副本的数据更新为最新版本。
    其实归根到底,反熵修复都是为了在这些选择了A(可用性),P(分区容错性)而放弃C(一致性)的分布式系统中,试着去提供一个最终一致性保证。(其实在没有网络分区的情况下,这些系统并没有放弃一致性)

1.Merkel Tree到底是什么

我第一眼看到采用Merkel Tree来进行反熵修复的时候,完全不理解这句话什么意思。那么我们就一步一步进行拆解,首先搞清楚Merkel Tree是什么,再来看什么是反熵修复。

1.1 Merkel Tree

Merkel Tree

Merkel树是一种二叉树,准确说是一种二叉哈希树。树中有两种节点,分别是叶子节点(leaf node)和内部节点(inner node);根节点是一个特殊的内部节点,没有父亲。所有的内部节点都仅仅只包含孩子节点的哈希值,而每个叶子节点则对应一个数据块,存放数据块的哈希值。
Merkel树可以很好的展示加密承诺这个概念,数据块是承诺的原始部分,而根节点就是承诺。用户可以通过检验根节点快速进行数据验证,而无需通过所有的数据块进行逐一计算。

1.2 Merkel Tree的应用

Merkel树最常见与P2P下载软件与区块链中。

  • 作为P2P下载时的数据验证
    在P2P下载中,下载者会预先从可信方得到 Merkel树根节点(其实就是一个Hash值),比如周知的“善意下载站”或者“口碑很好的朋友”。接着,下载者可以从任何不可信的地方接受一个完整的Merkel树;下载方可以对接收到的哈希树进行验证,如果计算出来的根节点与收信任的根节点一样,那么说明这是一个正确的哈希树。
    接着,下载者便可以从任意Peer节点下载数据块,并立即检查每个分支的正确性。比如,在上图中,下载者以及下载完了L1与L2,他就可以通过Hash0这个内部节点迅速验证数据块的正确性。
    下载完成后,会计算顶部哈希。如果最终计算出来的顶部哈希与预期的不一样,下载者也可以从顶层逐步向下寻找出错的数据块,进行重新下载。传统的计算整个文件的摘要得到H(File)的方式,一旦出错就需要重新下载整个文件,如果网络中存在恶意节点,那么很有可能下载者永远也没法完成下载。
    还记得我们之前说的“善意下载站”或者“口碑很好的朋友”吗?采用Merkel树可以让他们存储更多的信息!他们只需存储最顶层的一个哈希值而不是完整的数据承诺,就可以让用户自己验证数据是否正确。在互联网中好人不好找,那么就尽可能提升好人做好事的能力。
  • 作为区块链中交易的验证
    区块链的每一个区块都包含了大量的交易,每一个交易其实就对应了Merkel Tree的叶子节点,计算出的Merkel树根节点就会放在区块头中。
    区块链

    区块链的参与者分为轻节点与全节点,轻节点只存储每个区块链的链头,全节点才存储每个完整的区块。那么如果轻节点想要验证某一个交易是否被包含在某个区块中,怎么办呢?解决办法就是Merkel Path(Merkel路径)
    Merkle Tree Data Verification

    比如我们想验证Y这个交易是否被包含在某个区块上,那么我们只需要H(Z)、H(WX)的哈希(图中紫色节点),构成Merkel路径就可以证明。①获取交易Y的哈希值H(Y)②通过H(Z)的哈希值,计算得到H(YZ)③通过H(WX)得到根节点的哈希值H(WXYZ)④将根节点的哈希与区块头中的哈希进行对比,完成验证。

2. 反熵修复是什么

2.1 信息熵

每条信息中包含的信息的平均值,而信息的基本作用就是消除人们对事物的不确定性。一个系统越是有序,他的信息熵就越低;反之,一个系统越是混乱无序,信息熵就越高。因此信息熵也是系统有序化程度的一个度量。一个系统总是自发地向着熵增发展,而数据系统的存在就是为了使数据有序,这是一个熵减过程。因此,使系统从无序的状态变回有序的状态,就是反熵修复。

2.2 Gossip协议与Anti-Entropy

在Paxos为代表的分布式共识系统中,系统着重提供数据一致性、数据容错。而Gossip协议的系统着重考虑网络分区时的可用性、系统可拓展性,至于数据一致性,仅仅提供一种“宽松的一致性”即:最终一致性。Gossip协议被应用于以太坊网络、Cassandra数据库、Dynamo数据库、Docker Multi-host网络。
Gossip的设计目的是想在众多节点的数据系统中达成数据最终一致性。这样的分布式数据系统面领着很多困难和挑战。

  • 可能有成千上百个数据副本节点。
  • 数据项的更新可以只告知一个节点,而这一更新需要最终传播到所有节点上。
  • 数据节点分布广阔,遍布全球。

    这些挑战可以总结出两点①数据更新需要巨大的网络流量②数据更新到所有节点的时间会很长。为了解决这样的挑战,一个直观的解决方案是:一旦发生数据更新,那么接受更新的节点直接将数据变化情况告知系统中的所有节点。这一方法被称为Direct Mail。这种方法在很多场景下并不适合:①一个新的节点加入了网络,而数据更新者并不知道新节点的存在②网络分区,数据更新者无法与某些节点建立连接
    Direct Mail

    partition

而Gossip协议采用了如下设计思路:

Replace complex deterministic algorithms for replicated database consistency with simple randomized algorithms that require few guarantees from the underlying communication system

其实就是采用一种随机性的算法,来替代一个确定性的算法。并且乐观的希望这个随机性的算法可以实现一个最终一致性(最终这个词用的很妙,毕竟100年后实现一致性也算最终一致性)。采用随机性算法的好处是可以大幅减少数据系统的约束,不需要提供太多保证。
Gossip协议的雏形来自于这篇经典论文EPIDEMIC ALGORITHM FOR REPLICATED DATABASE MAINTENANCE,将信息更新的过程比瘟疫的传播。也正是在这篇论文中,作者第一次提出了Anti-entropy这一概念

 FOR SOME s1 belong to S DO
   ResolveDifference[S,s1)
 END LOOP

假设每个数据系统集合都定期执行Anti-entropy这一过程。每次执行,先随机选择集合S中的s1,s1再随机选取集合S中的任意其他节点,不断解决两两之间的数据冲突,最终整个集合中的对象都会达成数据一致性。接下来的一系列图就展示了一次反熵的过程。


反熵过程1
反熵过程2
反熵过程3
反熵过程4
反熵过程5
反熵过程6

反熵有一个非常明显的缺点:操作代价昂贵。每次ResolveDifference操作都需要对比两个完整的数据库副本(意味着对数据库所有条目都进行逐一比较)。论文中提出了一种优化方案,每个数据库副本都维护一个数据库内容的校验和。但这样的方式也会大量计算开销,并且执行反熵的时候只能直观的看出数据有不同,但不知道到底哪里的数据不同,最后还是得对数据库条目进行逐一比较。

2.3 Cassandra的反熵修复

对于Cassandra数据库来说,反熵修复其实就是指各个副本间的数据同步,来保证每个副本的数据都是最新的
上面那篇论文发布时,并没有Merkel Tree这个概念,因此我们视反熵为一个昂贵的操作过程。但是由于现在LSM Tree与Merkel Tree的存在,ResolveDifference操作的开销大大减少。下面就是Cassandra数据库中反熵修复的过程。

  • 为每个副本的数据库建立Merkel树,叶子节点对应一个SSTable或者内存表。由于内存表被设置了大小限制,旧数据都在已经持久化存储的SSTable中,发生数据更新也只影响内存表,即最右边的一个Merkel树叶子节点。
  • 对比Merkel树来找到不同的数据。参与验证的两个节点先对比Merkel Root,如果不同,则逐层往下对比中间节点,直到找出不同的叶子节点。接着,就可以替换副本上的旧数据。

你可能感兴趣的:(Merkel Tree与反熵修复(Anti-entropy repair))