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 }
  |