Lab 2: Key/Value Server
新版本 6.824 课程添加了一个 Lab 2,实现一个请求幂等的简单 KV 存储服务,还有对应的 Client 端。
幂等性:题目依赖的底层 RPC 网络是不可靠的。为此,在请求中携带一个递增的 Sequence Number,在服务端忽略每个 Client 的旧 Request 即可。
服务端实现:维护一个 map[int]int
,记录每一个 Client 发来的最大的 Sequence Number;注意 Append 命令还需要缓存执行的结果。
1 2 3 4 5 6 7 8
| type Last struct { Seq int Value string }
type KVServer struct { last map[int]Last }
|
Get 命令无需考虑幂等性,直接返回即可:
1 2 3 4 5
| func (kv *KVServer) Get(args *GetArgs, reply *GetReply) { kv.mu.Lock() defer kv.mu.Unlock() reply.Value = kv.store[args.Key] }
|
Put 命令需要保证幂等性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) { kv.mu.Lock() defer kv.mu.Unlock() if last, ok := kv.last[args.ClientId]; ok { if args.Seq < last.Seq { panic("seq < last") } if args.Seq == last.Seq { return } } kv.last[args.ClientId] = Last{Seq: args.Seq} kv.store[args.Key] = args.Value }
|
Append 命令不仅需要保证幂等性,还需要缓存执行的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) { kv.mu.Lock() defer kv.mu.Unlock() if last, ok := kv.last[args.ClientId]; ok { if args.Seq < last.Seq { panic("seq < last") } if args.Seq == last.Seq { reply.Value = last.Value return } } reply.Value = kv.store[args.Key] kv.last[args.ClientId] = Last{Seq: args.Seq, Value: kv.store[args.Key]} kv.store[args.Key] += args.Value }
|