Skip to content

6.824 Lab 3 KVRaft

Posted on:2022.08.12

TOC

Open TOC

lab3

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

basic (3A)

KV=1 go test -race -run TestBasic3A

并发测试

100
--tests
TestBasic3A
TestConcurrent3A
TestUnreliable3A
TestUnreliableOneKey3A
TestOnePartition3A
TestManyPartitionsOneClient3A
TestManyPartitionsManyClients3A
TestPersistOneClient3A
TestPersistConcurrent3A
TestPersistConcurrentUnreliable3A
TestPersistPartition3A
TestPersistPartitionUnreliable3A
TestPersistPartitionUnreliableLinearizable3A
--race

主要是利用 raft server 写一个能够容错的 kv service

client 有 GET / PUT / APPEND 方法,会通过 rpc 访问 server

server 则通过 lab2 暴露的接口与 raft server 交互

首先需要明确的是,lab2 实现的 raft server 实现的语义是 At-Least-Once,也就是说,对于一个 command,可能会被多次 apply

考虑如下情形,client 发送 command 给 raft,raft 在 apply 之后和响应 client 之前掉线了,那么 client 将会重发 command,然而该 command 实际已经存在于 raft log 中

所以,需要在 lab3 中实现 Exactly-Once 的语义,更具体的,需要实现 GET / PUT / APPEND 方法的 linearizability

为此,client 访问 server 时,需要提供 clientIdcommandId,其中

当 server 处理 client 的请求时,若该请求为重复的非读请求,则直接返回记录的结果

考虑到只有 PUT / APPEND 操作才会改变 KVServer 的状态

为此,每个 server 需要维护如下的数据结构

clientId -> (commandId, response)

记录每个 client 最近一次 command 的 response

否则,通过 Start 接口向 raft server 发起共识

直接发送整个 request 结构体,便于后面处理

最后通过返回的 index 索引对应的 channel,并阻塞读取

另外,server 需要一个 goroutine 监听来自 raft server 的 ApplyMsg

由于 Start 发送的 command 携带了全部 request 信息,所以仍然可以需要判断该请求是否为重复的非读请求

注意到 raft server 可能多次 commit (apply) 同一个 command,需要在 kv server 层 apply 之前进行去重

若否,就可以真正的改变 kv server 的状态了,然后通过 commandIndex 索引对应的 channel

在写入 channel 前,还需要利用 GetState 接口检查 raft 的 authority,为此需要在 ApplyMsg 中添加新的字段 commandTerm

一些细节

存在的问题

snapshot (3B)

KV=1 go test -race -run TestSnapshotRecoverManyClients3B | ./dslogs.py -c 5

并发测试

100
--tests
TestSnapshotRPC3B
TestSnapshotRecover3B
TestSnapshotRecoverManyClients3B
TestSnapshotUnreliable3B
TestSnapshotUnreliableRecover3B
TestSnapshotUnreliableRecoverConcurrentPartition3B
TestSnapshotUnreliableRecoverConcurrentPartitionLinearizable3B
--race

明确一下概念

kv serverraft server (persister)
statekv tablelog
snapshotkv table

kv server 通过调用 Snapshot 向 raft server 提供 snapshot

而调用的依据就是 raft server 的 state 大小,即 log 的大小

需要改动的地方如下

另外,除了 kv table,上述数据结构 clientId -> (commandId, response) 也是 state 的一部分

test

with -race

3A (without TestSpeed3A)

9e735f9087b742668896668aa13a4223.png

3B (without TestSnapshotSize3B and TestSpeed3B)

e4eecf1fcdc74927abcd645383ac6c60.png

存在的问题

ref

https://github.com/OneSizeFitsQuorum/MIT6.824-2021

https://frederick-s.github.io/2022/06/04/mit-6.824-lab3-implementation/

https://web.stanford.edu/~ouster/cgi-bin/papers/OngaroPhD.pdf

https://www.zhihu.com/question/278551592