实验简介
实现基于raft的KV服务器,您将需要修改kvraft / client.go
,kvraft / server.go
,甚至可能是kvraft / common.go
。
一定要保证lab2是正确的,不然这个实验到处是问题。
实验参考:
- https://www.cnblogs.com/mignet/p/6824_Lab_3_KVRaft_3A.html
- https://blog.csdn.net/Miracle_ma/article/details/80184594
Client
通过RPC调用server的服务,需要考虑两个问题?
- 如果call超时,那么client就会超时重发。如果是因为网络延迟,那么server就会收到两次命令,确保服务端只执行一次命令(多次append会导致逻辑错误)。使用类似TCP的序列号,来去重。
- client应记录raft的Leader,就不用每次循环去尝试
PutAppend和Get的逻辑是完全一样的
Server
server不能立即执行client的命令,而是把命令反应给raft服务,等raft状态机提交了该命令后,再执行。
Part 3A
TestBasic3A
写了个最简单的版本
func (kv *KVServer) PutAppend(args *PutAppendArgs, reply *PutAppendReply) {
// Your code here.
cmd := Op{
Key: args.Key,
Value: args.Value,
Option: args.Op,
}
reply.WrongLeader = false
_, _, isLeader := kv.rf.Start(cmd)
if isLeader == false {
reply.WrongLeader = true
return
}
// TODO : 这样做的话,每次只能处理一个请求
kv.mu.Lock()
defer kv.mu.Unlock()
select {
case cmd := <- kv.applyCh:
op := cmd.Command.(Op)
kv.doCmd(&op)
case <- time.After(500 * time.Millisecond):
reply.Err = ErrTimeOut
return
}
LogDebug("C%d-%d %s key%s success, req=%d", args.ClientId, args.RequestId, args.Op, args.Key)
}
有时会通不过,raft日志如下:
10:49:16.407109 Start():{
0 x 0 111 y Append 4 249}
10:49:16.482170 {
true {
0 x 0 111 y Append 4 249} 397}
10:49:16.482984 Start():{
0 x 0 112 y Append 4 250}
1