这篇文章记录一下做华盛顿大学的dslabs的过程,实验很有趣,分为四个实验,分别是:
- 简单的单机服务的精确一次性实现:太简单了本文不做记录
- 一个强一致性服务的实现
- paxos算法的实现
- 暂时没做到
lab1: Client-Server
这个实验很简单,主要是实现有网络障碍的单机版的精确一次性,把思路记录一下:
我们实现了一个服务(key-value store in this lab),client可以请求server命令,必须保证:
- server执行的顺序和client发出的顺序一致(可能有消息丢包)
- server对每个命令实现精确一次性执行
实现思路:
- 为client发送出来的每条消息带上一个 s e q seq seq号,这样我们只需要在server端以正确的 s e q seq seq号执行消息
- 客户端实现重发机制,一条消息如果没收到对应的相应,一直重发,只有在收到这条命令的结果才发送下条命令。
- server端记录最新一条已经处理的消息的
s
e
q
l
a
s
t
seq_{last}
seqlast和其结果
r
e
s
u
l
t
l
a
s
t
result_{last}
resultlast。如果有一条新消息进来了,其
s
e
q
=
s
1
seq=s_1
seq=s1。那么对应的处理逻辑就是:
- 如果client来的消息的序列号< s e q l a s t seq_{last} seqlast,说明消息搁置了,实际上客户端早已收到这条消息的结果了,要不然我也不会收到 s e q l a s t seq_{last} seqlast
- 如果client来的消息的序列号= s e q l a s t seq_{last} seqlast,说明可能上一条消息在返回client的路途中丢失,给其返回 r e s u l t l a s t result_{last} resultlast
- 如果client来的消息的序列号= s e q l a s t seq_{last} seqlast+1,说明来了最新一条消息,处理,并更新 s e q l a s t seq_{last} seqlast和其结果 r e s u l t l a s t result_{last} resultlast
- 如果client来的消息> s e q l a s t seq_{last} seqlast+1,说明seq+1这条消息在来的路上出现毛病了,我们需要等seq+1的消息,因此当前消息不处理
lab2: Primary-Backup Service
lab2主要是是从主从服务器实现一个强一致性的分布式系统,可以进行状态转移,lab2的思路是这样的:
- 有一个ViewServer,这个ViewServer可以看做是一个单机版的中心化注册中心,其作用是监听活动的server,从而选择出一个primary和一个backup。primary是client请求的主服务器,backup是primary的备份服务器,其状态必须与primary保持一致,以在primary挂了的时候顶上去。
- primary与backup的状态同步,这分为初始化backup和增量同步两个步骤:
- 初始化backup:假设一个primary正在正常运行,然后一个新的backup出现(可能是之前没有backup或者老backup挂了),此时primary需要将其状态拷贝一份给新backup帮助其初始化状态。
- 增量同步:在backup初始化好之后,此时client发送给primary一个命令。为了让primary与backup保持同步,primary需要先将这条命令发送给backup执行之后,再发送给client。
- 实验的注意事项:
通过这个实验,真实地体会了分布式事务的复杂性,因为你需要考虑很多种失败情况(宕机、网络错误等),其中包括:- viewserver更新view的问题:primary超时、backup超时、记录活动的服务器(可能有很多服务器ping了viewserver,需要记录下来以在primary或backup超时之后迅速找到其他服务器顶上去)、在primary回应后才能进入下一个版本的view(lab要求)
- primary初始化backup:我选择的是将primary的整个状态都发送给backup(这里需要考虑重发机制:如果初始化信息丢包了怎么办)
- primary与backup执行命令的问题:primary与backup执行命令的顺序要完全一致:举个例子,primary收到client的消息 m 1 m_1 m1和 m 2 m_2 m2,将其发送给backup,由于网络传输因素,backup接收到消息顺序是 m 2 m_2 m2, m 1 m_1 m1,这就会导致backup与primary执行的顺序不一致,我在这里是为每个消息设置了一个 P B S e q PBSeq PBSeq来强制backup执行和primary一致的命令。
- primary与backup执行命令的问题:需要考虑很多种丢包的可能性:primary发送给backup的命令丢包?backup发送给primary的执行结果丢包?为了实现这个,primary和backup都需要实现精确一次性语义。
- client的通信流程:client需要知道当前的primary是哪个服务器。我的实现如下:client给当前primary发送消息,并为这条消息设置计时器,如果计时器时间到了还没收到回复,client有理由认为当前primary已经挂了,此时client就会向viewserver请求当前的view(primary, backup)。通过这个机制实现client能动态地知道当前primary的地址。