<1>pbft五阶段请求解释

Request  pre-prepare   prepare   commit  执行并reply

(1)pre-prepare阶段:

主节点收到客户端请求,给请求编号,并发送pre-pre类型信息给其他从节点。

从1节点收到pre-pre类型信息,如果同意这个请求的编号,如果同意就进入prepare阶段

(2)Prepare阶段:

从1节点同意主节点请求的编号,将发送prepare类型消息给主节点和其他两个从节点。如果不发,表示不同意。

图:从1节点发prepare信息给其他节点

从1节点如果收到另外两个从节点都发出的同意主节点分配的编号的prepare类型的消息,则表示从1节点的状态为prepared,该节点会拥有一个prepared认证证书。

为了防止viewchange导致主节点给请求分配的编号失效,引入commit阶段。

(3)commit阶段

从1节点进入prepared状态后,将发送一条COMMIT类型信息给其它所有节点告诉他们它有一个prepared认证证书了。

图:从1节点发commit类型信息给其他节点

如果从1节点收到2f+1条commit信息,证明从1节点已经进入commited状态。

只通过这一个节点,我们就能认为客户端的请求在需要的节点中都到达了prepared状态,每一个需要的节点都同意了主节点分配的编号。当一个请求在某个节点中到达commited状态后,该请求就会被该节点执行。

问:为什么要有commit阶段?

答:commit阶段用来确保其他节点都已经收到足够多的信息来达成共识了。Commit阶段并没有像prepare阶段发送同意不同意请求,只检测有没有收到足够多的commit类型信息。

相当于是正常情况下,4个节点中,如果每个节点都同意了请求,并且收到另外三个节点的同意信息。

所以如果从1节点正常情况下达到了commited阶段,确保了实际收集的信息相当于是:

节点    收到同意编号数

主节点    4

从1      4

从2      4

从3      4

这时从1节点可以放心执行客户端的请求,写入新区块了,因为其他节点都已经收到足够多的信息来达成共识了。

如果从1节点达到了prepared阶段,实际每个节点收集到的信息可能是:

节点    收到同意编号数

主节点   2

从1     4

从2     1

从3     1

这时其他节点并不能确保已经收到足够多的同意信息,从数据验证的角度是不应该写入新区块的。这才是问题的关键。这时如果发生view change,会丢弃prepare阶段的请求。

问:如果在commit阶段view change,会导致达成不了共识吗?会导致之前的view下的请求编号丢失吗?

答:如果commit阶段viewchange,会保留之前commit阶段的请求,不会达成不了共识,也不会丢失请求编号。

解释:prepare阶段和commit阶段用来确保那些已经达到commit状态的请求即使在发生viewchange后在新的view里依然保持原有的序列不变,比如一开始在view 0中,共有req 0, req 1, req2三个请求依次进入了commit阶段,假设没有坏节点,那么这四个replicas即将要依次执行者三条请求并返回给Client。但这时主节点问题导致view change的发生,view 0 变成 view 1,在新的view里,原本的req 0, req1, req2三条请求的序列被保留,作数。那些处于pre-prepare和prepare阶段的请求在view change发生后,在新的view里都将被遗弃,不作数。

这个意思其实是:

如果每个节点都进入了commit阶段(这里要强调的是每个节点都进入这个commit阶段才算是整体进入了commit阶段),这时即使view change,也会保留之前的view里进入commit阶段的请求信息,view change会继续之前的commit阶段请求,不会再重新进入pre-prepare和prepare阶段。

问:为什么fabric0.6和1.0都要共识交易的顺序?0.6是pbft实现,1.0是order负责排序。每笔交易的顺序为什么需要共识?不能按照时间顺序存在一个队列里顺序执行就可以了吗?

答:考虑两种情况,有可能会导致每个节点收到的顺序不一样。

第一类:节点收到的顺序和单个客户端发起的顺序不一样

假如客户端发起请求的正确顺序:123

4个节点收到的顺序有可能是:

情况1

主节点:123

从节点1:123

从节点2:132

从节点3:123

情况2

主节点:132

从节点1:123

从节点2:123

从节点3:123

第二类:多个客户端同时发起请求,每个节点收到的顺序不一样的可能性增大

这样共识出来的结果,有可能未必是每个客户端的正确顺序。比如a发起请求1,b发起请求2. 1和2是有关系的。但是a到集群的时间很长,b到集群的时间很慢,导致集群收到的请求都是21,这样共识出来的结果是21,而不是实际应该的12,遇到这种情况,要有机制能判断是错误的,丢弃这样的请求,并返回错误信息。这种情况可以举个例子:

如果初始状态为a:10,b:0,c:0,a转b10元为请求1,b转c10元为请求2,正确请求顺序为12,如果集群达成共识的请求的为21,这样就会和正确请求顺序产生差异。丢弃2的请求。因为b这时并没有10元可以转给c。如果初始状态为a:10,b:10,c:0,集群达成共识的请求为21也可以正常执行。因为b最初已经有10元,可以转给c。请求之间有强依赖的另一例子就是特定物权的转移,因为那件物品只有一个,任意一方没有拥有这件物品时,是无法转给对方的。

而利用pbft算法,情况1和2都能共识出正确顺序结果应该为123。主节点为错误请求时,会导致view change变成情况1的情况,情况1能共识出123为大多数节点认可的结果。

扩展:

为什么不能直接用每个客户端的时间作为请求的排序,因为每个客户端的时间可以任意更改的,如果大家都更改到不一样的时间,这样的请求的顺序是错误的。如果去统一的时间戳服务去取时间,又会多了一个中心化节点。所以google spanner分布式数据库就在全球统一的时间戳服务这个点去入手解决一致性请求顺序的问题。

注:Google Spanner是个可扩展,多版本,全球分布式还支持同步复制的数据库。他是Google的第一个可以全球扩展并且支持外部一致的事务。Spanner能做到这些,离不开一个用GPS和原子钟实现的时间API。这个API能将数据中心之间的时间同步精确到10ms以内。因此有几个给力的功能:无锁读事务,原子schema修改,读历史数据无block。

<2>Checkpoint和高低水位:

分布式系统的复杂性在于要考虑到各种各样的意外和蓄意破坏,你要制定出一套有效的法律来约束这个系统里可能发生的一切行为,并没有完美的分布式系统存在。
   当replica执行完请求时,需要把之前记录的该请求的信息清除掉。但是不能这样轻易的去清除,其中包含的prepared certificate可能会在后面用得上。所以要有种机制来保证何时可以清除。
    其实很简单,每执行完一条请求,该节点会再一次发出广播,就是否可以清除信息在全网达成一致。更好的方案是,我们一连执行了K条请求,在第K条请求执行完时,向全网发起广播,告诉大家它已经将这K条执行完毕,要是大家反馈说这K条我们也执行完毕了,那就可以删除这K条的信息了,接下来再执行K条,完成后再发起一次广播,即每隔K条发起一次全网共识,这个概念叫checkpoint,每隔K条去征求一下大家的意见,要是获得了大多数的认同(a quorum certificate with 2 f + 1 CHECKPOINT messages (including itsown)),就形成了一个 stablecheckpoint(记录在第K条的编号),我们也说该replica拥有了一个stablecertificate就可以删除这K条请求的信息了(即删除k之前的请求)。
    这是理想的情况,实际上当replica i向全网发出checkpoint共识后,其他节点可能并没有那么快也执行完这K条请求,所以replica i不会立即得到响应,它还要继续自己的步伐,那这个checkpoint在它那里就不是stable的。那这个步伐快的replica可能会越来越快,可能会把大家拉的越来越远,这时我们来看一下上面提到的高低水位的作用。对该replica来说,它的低水位h等于它上一个stable checkpoint的编号,高水位H=h+L,L是我们指定的数值,它一般是checkpoint周期K的常数倍(这个常数是比较小的,比如2倍),这样即使该replica步伐很快,它处理的请求编号达到高水位H后也得停一停自己的脚步,直到它的stable checkpoint发生变化,它才能继续向前。

注:主节点是坏的,它在给请求编号时故意选择了一个很大的编号,以至于超出了序号的范围,所以我们需要设置一个低水位(low water mark)h和高水位(high water mark)H,让主节点分配的编号在h和H之间,不能肆意分配。

例子:

假设低水位h为,0,高水位H为100,L为100.checkpoint为50,上个stablecheckpoint为150.表示集群每隔50个请求就全网共识下大家确认的请求的情况。

如果节点A已经确认到编号为250了,其他节点才确认到编号为180,则节点A需要等待。直到其他节点确认的编号大于200.于是使得stable checkpoint从150变成200后,节点A才能继续确认编号250以后的请求。

通信次数分析:

pbft算法:

本质需要两个大阶段,一个是准备,一个是确认。进入prepared阶段,需要n^2次 ,进入commited阶段也需要n^2次,所以总次数为2n^2,o(n)为 n^2。

优点:容错算法,如果主节点为作恶节点也能检查出来。

缺点:需要确认和通信的次数较多。

raft算法:

在选好主节点的情况下,其他从节点相当于是被动的复制,所以需要通信次数为n次即可。o(n)为 =n。

优点:容易理解,通信次数比较少。

缺点:如果主节点为作恶节点,无法检查出来。

注:n为节点数,一次通信包括请求和响应

pbft流程深层分析和解释(转)的更多相关文章

  1. Ecshop的购物流程代码分析详细说明

    Ecshop的购物流程代码分析详细说明 (2012-07-30 10:41:12) 转载▼ 标签: 购物车 结算中心 商品价格 ecshop ecshop购物流程 杂谈 分类: ECSHOP研究院 同 ...

  2. ElasticSearch评分分析 explian 解释和一些查询理解

    ElasticSearch评分分析 explian 解释和一些查询理解 按照es-ik分析器安装了ik分词器.创建索引:PUT /index_ik_test.索引包含2个字段:content和nick ...

  3. Openfire注册流程代码分析

    Openfire注册流程代码分析 一.客户端/服务端注册用户流程 经过主机连接消息确认后,客户端共发送俩条XML完成注册过程.服务器返回两条XML. 注:IQ消息节点用于处理用户的注册.好友.分组.获 ...

  4. Linux Kernel文件系统写I/O流程代码分析(二)bdi_writeback

    Linux Kernel文件系统写I/O流程代码分析(二)bdi_writeback 上一篇# Linux Kernel文件系统写I/O流程代码分析(一),我们看到Buffered IO,写操作写入到 ...

  5. Linux Kernel文件系统写I/O流程代码分析(一)

    Linux Kernel文件系统写I/O流程代码分析(一) 在Linux VFS机制简析(二)这篇博客上介绍了struct address_space_operations里底层文件系统需要实现的操作 ...

  6. DB2 锁问题分析与解释

    DB2 锁问题分析与解释 DB2 应用中常常会遇到锁超时与死锁现象,那么这样的现象产生的原因是什么呢.本文以试验的形式模拟锁等待.锁超时.死锁现象.并给出这些现象的根本原因. 试验环境: DB2 v9 ...

  7. Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Job Manager 启动

    Job Manager 启动 https://t.zsxq.com/AurR3rN 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac ...

  8. Flink 源码解析 —— Standalone Session Cluster 启动流程深度分析之 Task Manager 启动

    Task Manager 启动 https://t.zsxq.com/qjEUFau 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Ma ...

  9. [精] UBOOT2017+FIT 启动流程详尽分析

    开发环境:Nanopi-neo-plus2 软件版本:uboot-2017 软件版本:linux-4.14 买这个板子有一段时间了,并没有全身心的投入在上面,有时间了的话就搞一搞, 这篇随笔算是对这个 ...

随机推荐

  1. Volley 结合GSON或FastJson用法

    自定义GSON类 public class GsonRequest<T> extends Request<T> { private final Gson mGson = new ...

  2. 在html中用js代替${pagecontext.request.getcontextpath}这样就不用使用jsp了

    var pathArray = window.location.pathname.split('/');  var secondLevelLocation = pathArray[1];  var l ...

  3. python中编码问题

    各种编码在内存中所占的大小: ascii: 英文:8bit (1B) uft-: 英文:8bit (1B) 中文:24bit (3B) GBK: 英文:8bit (1B) 中文:16bit (2B) ...

  4. c#数组用法

    随机数: string[]  str = new string[4]{"a","b","c","d"} Readom r ...

  5. for循环.html

    <script> for (var i = 1; i < 5 ; i++) { alert(i); } 公式需要记住,并多加练习,加深记忆,注意编写格式 for (var i = 1 ...

  6. boost 学习笔记 1: lexical_cast

    参考原著地址:http://einverne.github.io/post/2015/12/boost-learning-note-1.html 转换对象要求 lexical_cast 对转换对象有如 ...

  7. Android仿淘宝头条滚动广告条

    之前我使用TextView+Handler+动画,实现了一个简单的仿淘宝广告条的滚动,https://download.csdn.net/download/qq_35605213/9660825: 无 ...

  8. Windows Server 2016 启用完整版任务管理器

    众所周知 Windows Server 2012以上的任务管理器是被阉割过的 那么如何启用呢?首先把你的任务管理器复制一份出来位置:系统盘\Windows\System32\Taskmgr.exe和系 ...

  9. LRU简单实现

    用LinkedHashMap来实现 package com.yin.purchase.dao; import java.util.ArrayList; import java.util.Collect ...

  10. github提交代码后没有contribution问题

    好气啊,好几天的代码提交后发现没有contribution,强迫症表示不能忍,仔细排查了下原因 可能有以下几个原因 1.提交代码的用户名和邮箱和账号不符合 方法1:git命令行设置用户名和邮箱 git ...