Skip to content

Lab‐3 Intro

M1ng edited this page Jan 20, 2024 · 4 revisions

kv

https://pdos.csail.mit.edu/6.824/labs/lab-kvraft.html

在本实验中,您将使用第二实验中的Raft库构建一个容错的键值存储服务。您的键值服务将是一个复制状态机,由多个使用Raft进行复制的键值服务器组成。您的键值服务应在大多数服务器仍然存活且能够通信的情况下继续处理客户端请求,即使存在其他故障或网络分区。完成实验3后,您将已经实现了Raft交互图中显示的所有部分(Clerk、Service和Raft)。

客户端可以向键值服务发送三种不同的RPC:Put(key, value)、Append(key, arg)和Get(key)。服务维护一个简单的键值对数据库,其中键和值都是字符串。Put(key, value)用于替换数据库中特定键的值,Append(key, arg)用于将arg追加到键的值,Get(key)用于获取键的当前值。对于不存在的键的Get应返回空字符串。对不存在的键的Append应像Put一样操作。每个客户端通过一个具有Put/Append/Get方法的Clerk与服务进行通信。Clerk管理与服务器的RPC交互。

您的服务必须确保对Clerk Get/Put/Append方法的应用调用是线性可比的。如果一次只调用一个Get/Put/Append方法,那么这些方法应该表现得好像系统只有一个副本的状态,并且每个调用应该观察到由前面一系列调用隐含的状态修改。对于并发调用,返回值和最终状态必须与以某种顺序一次执行这些操作时的相同。调用在时间上重叠时为并发调用,例如,如果客户端X调用Clerk.Put(),客户端Y调用Clerk.Append(),然后客户端X的调用返回。调用必须观察到在调用开始之前已完成的所有调用的效果。

线性可比性对应用程序很方便,因为它是从一台一次处理请求的单个服务器中看到的行为。例如,如果一个客户端对更新请求收到了服务的成功响应,随后由其他客户端启动的读取将确保看到该更新的效果。提供线性可比性对于单个服务器相对容易。如果服务是复制的,则更难,因为所有服务器必须选择并发请求的相同执行顺序,必须避免使用不是最新的状态回复给客户端,并且必须在故障后以保留所有确认的客户端更新的方式恢复其状态。

此实验有两个部分。在A部分,您将使用Raft实现实现一个键值服务,但不使用快照。在B部分,您将使用第2D实验的快照实现,该实现允许Raft丢弃旧的日志条目。

注意事项(实验教程中的Hint)

1、服务端在接受到客户端的请求后,将操作通过Start函数进行raft共识,服务端必须要等到该操作的共识结果出来后,才能进行返回消息给客户端。同时,服务端需要实时关注applyCh中的完成共识的操作,并及时进行执行。同时要避免kvraft和raft之间的锁的造成的死锁问题。

2、我们可以根据自己的设计来修改raft中的applyMsg的数据结构,但是这并非是必要的。

3、服务端在处理get操作的时候,必须确保get返回的值是最新的,即get前面的修改数据的操作都已经执行。一个简单的方法就是将get也看做为修改数据的操作,需要经过共识放到applyCh才能执行。当然也可以进行优化,针对这种read-only的操作特别设计机制,可以参考论文中的section8.

4、注意避免死锁,注意使用 -race来侦查数据竞争问题

5、需要注意一种情况,当客户端发送给一个过时的领导者(可能是发生分区 ,已经 有了一个更高term的领导者),这个过时的领导者收到请求后进行共识。应对这种情况,一种解决方法:raft节点注意到自己不是领导者了,立即停止共识并通知客户端。如果是发生了分区,客户端和这个过时的领导者被分到了同个分区,那么客户端将无法和最新的领导者进行连接,那么就只能等到网络分区恢复,然后客户端和正确的领导者建立连接。

6、客户端应该能够存储leader的索引,简单来说就是经过一次搜索leader的索引后,之后的就认定这个索引index,servers[index]为leader,后续请求操作向servers[index]发起rpc操作即可。

7、需要给客户端发送的每个请求都赋予一个独一无二的标识符,避免网络丢包等问题带来的,修改操作执行二次的问题,服务器每次仅需查看该请求的标识符,即可判断该请求是否执行过。

8、对于那些重复的请求,服务端能够做到快速回复的机制。但是需要确保这个机制要及时释放内存,实验中kvserver在接受到一个rpc请求后就表明之前的rpc请求都已经收到回复,不会再出现重复请求的问题。

9、在kvserver进行快照时,需要认真考虑需要保存哪些数据到快照里面。raft存储快照数据是使用SaveStateAndSnapshot()函数,读取最新的快照数据是使用ReadSnapshot()函数。

10、在kvserver进行快照的时候,需要注意和快速回复重复请求机制有关的数据也需要保存,避免服务端崩溃重启后,重复执行请求。

11、需要进行快照的数据的数据结构的首字母大写。

12、如果在本实验中发现了raft实现中的一些bug,修复后请重新把lab 2测试跑一遍。

13、lab3全部测试应该在400秒的real time,700s的cpu time以内。此外,TestSnapshotSize应该在20秒以内通过。

Clone this wiki locally