zoukankan      html  css  js  c++  java
  • 关于共识机制的一些想法

    前言

    之前搞过一段时间并行计算相关的东西,写过一些Lock-Free的代码。接触以太坊社区之后,看到了共识机制的概念。当时就感觉这两者之间一定有什么联系。
    刚好没几天,就在知乎上看到有一个Lock-Free的问题,下面张德力回答里面提到了:

    无锁算法 (lock-free algorithm) 和 无等待算法 (wait-free algorithm) 的近代起源可以追溯到Herlihy的论文 Wait-free synchronization,1991。论文的核心在于用解决共识协议 (consensus protocol) 的能力来衡量同步原语的同步能力。

    花了周末的两天的时间看了个大概,下面大概介绍一下主要内容。考虑到有些非程序员读者,我会尽量多举例来说明。

    主要内容

    首先论文引入一个共识数 (consensus number) 的概念,用来衡量同步原语的能力。这个概念其实很简单,就是该原语最多能处理多少个节点的共识问题。

    最简单的原语,寄存器的原子操作,其共识数为1。
    因为它能解决一个节点的共识问题,这个不言自明。
    而它解决不了两个节点的共识问题。
    举个简单的例子,我和少平吃完饭之后,争着买单。我说:我来吧。少平一把把我推开说:还是我来吧。然后我再把他推开。。。
    如此下去,如果服务员耐心足够好的话,这个争论将一直持续下去,无法就谁来买单问题达成共识。

    然后是 Read-Modify-Write 原语(读取寄存器的值,对其进行修改操作,然后将结果写回去)。
    其共识数是2,也就是说它可以解决两个节点的共识问题。
    还用买单的例子来说明:这时两个人的做法是,先把钱拿出来,放在各自面前。然后去改账单,把账单上的金额减去自己拿出来的钱(付钱),然后把余额写回去。
    比如账单是100元。我和少平各拿100元放在自己面前。少平抢先拿到账单,把账单上的100改成0,我后拿到账单,把0改成-100。
    这时结果就很明显了,因为少平改之前账单上的数字是最初的100,他知道他抢到了这次付账的机会。我修改之前账单上的数字已经不是100了,所以我也知道是少平抢到了这次机会。
    但是这个原语无法解决两个以上的节点的共识问题。
    假如还有第三个人,无论我和少平谁先谁后,第三个人拿到账单的时候,上面的值都是-100,从而无法判断少平和我之间谁抢到了这次机会。情况就又回到第一段描述的情景中。
    我们可以看到RMW之所以无法解决三个人的共识问题,是因为前两个人选择的修改函数是可交换的。
    如果这两个函数是不可交换的,其实是OK的。但是理论就是理论,有一点瑕疵也不行。

    其实上一段的例子中有些操作是多余的,只要稍作改变,是可以解决三个人的共识问题的。
    只要把修改账单上的金额,改成在账单上签名就可以了。
    最开始账单上签名栏是空白的,谁先在上面签上自己的名字,就是谁买单。其他人只要看账单的签名栏是不是已经有人签名了就可以了。
    而且这个规则是可以解决任意多人抢单的问题的。
    这个操作其实就是大名鼎鼎的CAS原语(compare and swap),它的共识数是无穷。也就是说它可以解决任意多个节点的共识问题。
    举个应用的例子,用它来实现寄存器加一操作的流程是:
    1. 先获取寄存器的值,然后把这个值加一。
    2. 接着执行CAS操作时会比较当前寄存器的值是不是第一步时获取的值,如果是,则执行第三步;如果不是,说明在此期间其他节点已经修改过寄存器的值,则回到第一步,重新开始。
    3. 将加一之后的值写入寄存器。

    还有另外一种思路来改进RMW。
    我们可以看到RMW的精髓是将我和少平的争端,在账单金额的修改上安排了一次短兵相接。
    只有两个人的时候,一次短兵相接,谁胜谁负就知道了。
    但是三个甚至更多人的时候就变成混战了,即便最后只有一个人站着,其他人也不一定服他是第一。
    更好的方式是循环赛。每个人都跟其他人打一次。把所有场次的胜负关系整理一下,胜率最高的那个人就是第一。
    论文3.6节里面就是用的这个思路。
    原来我理解错了,这里并不是用n个原子寄存器,而是指同时写n个寄存器是原子操作。
    实际上这里用到的寄存器数目是 1+2+...+n 个,这也是n个队伍进行循环赛需要比赛的场次。
    这些寄存器摆成一个斜的三角形,通过n个寄存器同时赋值,就相当于循环赛所有的场次同时进行。
    这里还是有优化的余地,m个寄存器同时赋值其实可以解决2m-2个节点的共识问题。
    方法是2m-2个节点两两分组,分成m-1个组。
    组内先用RMW的方式决出一个优胜者。这样就只剩下m-1个优胜者,然后采用循环赛的思路,就可以得到最终胜出的人。

    两层共识

    一层是在不考虑拜占庭问题时,单纯的因为多节点同时读写导致的数据一致性问题。
    支持多点读写的数据库也会有这样的问题,解决方法是比较序列号,以最新的数据为准。
    区块链里面则是以最长链为准。大家都选择在最长的链条后面挖矿。一旦发现有更长的链条出现,马上放弃手头的工作,转换到新的最长的链条。
    这个就是上面提到的CAS的思路。

    另外一层是考虑拜占庭问题,节点可能因为网络延迟或者故障,甚至是主动的恶意行为,不遵循最长链的原则,导致数据出现分叉。
    这时候就靠POW或POS了,大家以算力或者股权背书,赌自己认为正确的分支。
    分布式数据库一般只处理简单的fail-stop故障,剩下的恶意攻击等情况,通过对节点的强管控,在外部系统中解决。

    为什么需要共识

    区块链技术或者更宽泛的去中心化的技术有一个很大的优势。套用网易的广告词就是:网聚人的力量。
    给我印象最深的就是预言机的概念。收集大家提交的答案,通过奖罚机制,就能得到现实世界中一个客观信息的准确数据。
    但是我一直在思考,区块链技术到底能从大家身上网聚到什么有价值的东西呢?
    区块链作为一个公共账本,已经得到金融业的关注。预言机可以获取客观信息。
    除此之外感觉应用上很受限制,没有太多用武之地。

    后来我终于觉得有点相通了。
    共识问题其实有点像机器学习或者统计学。
    简单的例子就是调查问卷,通过对一部分人(样本)的调查,来推断一个群体(整体空间)的真实情况。
    这里很严重的两个问题就是:样本偏差和模型选择偏差。
    如果样本太少,或者样本没有代表性,将无法得出正确的结论。
    如果对群体的概率分布有一个事先的错误判断,即使得到翔实的数据,也会对数据进行错误的解读,得到错误的结论。

    这也是区块链在应用方面面临的问题。
    我看到有文章质疑augur的作用,担心落入自我预言的漩涡。
    解决方法,也可以借鉴统计学的一些结论。
    对于样本,肯定要尽可能的多。只能拼命抢地盘啦。
    对于模型的选择,这个就要具体情况具体分析了。

    更长远的来看,其实是计算机网络向现实世界全方位的渗透。
    最终结局就像大家说过的那样,成为终结者中的天网。

  • 相关阅读:
    winRT Com组件开发流程总结
    win32 COM组件编写
    windows8 APP开发的远程调试
    VS2012中,C# 配置文件读取 + C#多个工程共享共有变量 + 整理using语句
    STL源码--序列式容器
    代码规范
    Visual Studio Code 断点调试配置方法(请按我的步骤 一定可以做到)
    CSS层级关系 学习笔记
    VUE 学习笔记
    CSS 学习笔记
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13313526.html
Copyright © 2011-2022 走看看