分布式容错
区块链,有一种理解为分布式统一账本,那么分布式的架构肯定会存在一个容错的问题。这里简单概述下容错相关内容。
分布式容错约定概念:
节点:在一个网络中,每一台终端计算机称为一个节点,传统架构中服务器\客户端的模式,那么服务器也看作一个节点。
消息:网络中节点单独工作,协作在一块,需要一种机制,称为消息,也作为消息传递。
消息丢失:网络中不能保证所有消息都是能正常被传递和确认,这个原因是由于网络中的带宽、物理设备故障、恶意节点等原因,故无法保证所有的消息都是能正常传递和确认,那么必然存在消息丢失。
消息确认:在消息传递的过程中,接收消息的节点接收到消息后返回一个确认信息给发送节点。
消息传递序号:在消息发送过程中,为了防止重复发送的统一消息,在消息传递中加一个序列号。
状态复制:在分布式系统中,串形复制命令序列。
加锁:串行状态复制的时候,通过加锁的方式保证单一执行修改。
票:弱化形式的锁。检查服务节点状态,不对其进行加锁。
上述大致说明了一些分布式容错的约定概念。接下来简单介绍下一些协议。
理想化的两阶段协议
step-1
客户端发起请求至所有分布式的服务器
step-2
if
发起请求的客户端获得了所有的服务器的锁
then
客户端一次发送消息,结束后解锁
else
客户端未获得所有服务器的锁
重新进入step-1
end
这是一个理想化的模式。类似数据库系统,第一阶段就是事务的准备阶段,第二年阶段就是提交或者回滚。
问题:
那么通过两阶段,出现节点故障的状态,那么请求无法完全,理想化的两阶段协议必须要求节点都正常,如果只是一部分服务器处于锁的状态,将无法正常完成整个过程。且客户端将无法判断服务器节点锁的状态,导致系统出现故障,问题:如何有效解决这种这种模式?
PAXOS
在票上加一个序列号,服务节点在收到票的时候记录票的序号,保证票不重复和本地记录的一致。通过超过半数的票来作为容错机制。
票协议:
step-1
客户端向所有节点发送带序号的票
step-2
if
客户端收到半数服务节点收到票的回复
then
客户端再次发起票,且加上命令消息一起发送给所有服务器
服务器节点收到消息,判断票有效性后,存储命令消息
服务器返回客户端信息
else
客户端等待,返回step-1
end if
step-3
if
客户端收到半数服务器的返回客户端消息
客户端通知所有服务器执行之前的命令
else
客户端等待,返回step-1
end if
这种票协议还是会出现服务节点存储本地票号,但是客户端在发起请求的时候票号会不一致,且命令存储会出现不一致。故再对这种模式进行改进。
PAXOS大致流程:
引入本地记录票号的计数、半数确认容错。
服务端客户端
初始化初始化
票号t=0、命令c票号Tmax=0、命令C、存储命令的票Tc
step-1step-1
发起请求、t=t+1,请求票号为t
服务节点判断:t>Tmax、那么Tmax=t,回复确认(Tc、C)
step-2step-2
客户端如果收到半数服务节点回复确认、选择(Tc、C)验证Tc>0、那么c=C、发送消息p(t、c )
服务节点收到p、判断t=Tmax、那么C=c、Tc=t、回复成功
step-3step-3
接收到半数以上服务节点回复成功,向每个服务节点发送执行c操作
说明:
PAXOS中有三阶段,三角色(提案者、接收者、学习者)
上述流程中一个p(t、c)称为一个提案,那么提案根据算法存储在半数以上的服务器,那么后续再出现新的p(t、c)则因为t的顺序判断,故会顺序执行。可以通过反证法,同时出现两个p(t、c)出现在服务节点,且都超过半数,那么两个p提案在服务器之间肯定会有一个不为空的交集。根据两个p中t的顺序号,那么肯定有一个p提案被存储在服务器节点中,成为有效提案。在step-2中t为判断为与最高票编号比较,于是执行之前已经存储的p提案中的c命令。
场景分析:
如果成功p提案的客户端没有故障,那么直接告诉所有服务器执行命令c
如果客户端在没有告诉服务器执行命令的已经出现故障,那么服务器等待下一个客户端获得提案再执行命令。后续客户端发送请求的时候,服务器即可告诉客户端之前有一个提案待执行,避免再次发送提案。
如果一般服务器出现故障,没有达到半数,客户端无法正常获得回复工作。
如果出现执行多命令情景,那么引入实例、增加实例编号,c命令选中执行,客户端通过新的实例编号来启动新的实例。且服务器通过询问附近服务器确认一致的决议。
算法中p2p网络环境下,每一个节点可以是单一角色、也可以是多个角色。
Leslie Lamport在1989年提出PAXOS有兴趣可以看看论文原文。