MIT6.5840-2023-Lab3B: Fault-tolerant K/V Service-Key/value service with snapshots

MIT6.5840-2023-Lab3B: Fault-tolerant K/V Service-Key/value service with snapshots_第1张图片

实验内容

使用 lab2 中的 Raft 库构建 Fault-tolerant K/V Service,即维护一个简单的键/值对数据库,其中键和值都是字符串。具体来说,该服务是一个复制状态机,由多个使用 Raft 进行复制的键/值服务器组成,只要大多数服务器处于活动状态并且可以通信,该服务就应该继续处理客户端请求。

实验环境

OS:WSL-Ubuntu-18.04
golang:go1.17.6 linux/amd64

Part B: Key/value service with snapshots

修改 KVServer 与 raft 合作,以节省日志空间,并使用 Lab 2d 的 raft 的 Snapshot() 方法减少重新启动时间。
测试时会给 StartKVServer() 传递 maxraftstate 参数,它表明持久化的 Raft 状态的最大以字节数(包括日志,但不包括快照);因此若调用 persister.RaftStateSize() 后发现当前持久化状态大小接近阈值 maxraftstate 的话,就应该调用 Raft 的 Snapshot() 方法来保存快照;若 maxraftstate 为 -1,表明不必创建快照。
所有 kvserver 收到 ApplyMsg 都会执行相应的命令,其中 kvserver leader 将执行结果通知 waitCh;kvserver follower 会收到由 leader 发来的快照更新自身状态。
除此以外,所有 kvserver 收到 ApplyMsg 执行相应的命令后(命令被过半数 raft 提交),应该检查自身持久化状态大小,并根据上述条件及时保存快照。

读取持久化状态

快照内容:kvs 和 lastReq

func (kv *KVServer) readPersist(data []byte) {
	if data == nil || len(data) < 1 { // bootstrap without any state?
		return
	}

	r := bytes.NewBuffer(data)
	d := labgob.NewDecoder(r)
	var kvs map[string]string
	var lastReq map[int64]int64
	if d.Decode(&kvs) != nil ||
		d.Decode(&lastReq) != nil {
		log.Println("decode fail")
	} else {
		kv.kvs = kvs
		kv.lastReq = lastReq
		log.Println("restore success")
	}
}

接收 applyCh 中的快照信息

func (kv *KVServer) apply() {
	for kv.killed() == false {
		applyMsg := <-kv.applyCh
		kv.mu.Lock()
		if applyMsg.CommandValid {
			if applyMsg.CommandIndex <= kv.lastIncludedIndex {
				kv.mu.Unlock()
				continue
			}

			if op, ok := applyMsg.Command.(Op); ok {
				log.Println("exec command")
				kv.exec(&op)
				term, isLeader := kv.rf.GetState()
				if isLeader && applyMsg.CommandTerm == term {
					if waitCh, ok := kv.waitCh[applyMsg.CommandIndex]; ok {
						waitCh <- &op
					}
				}

				if kv.maxraftstate != -1 && kv.persister.RaftStateSize() >= kv.maxraftstate {
					w := new(bytes.Buffer)
					e := labgob.NewEncoder(w)
					e.Encode(kv.kvs)
					e.Encode(kv.lastReq)
					kvstate := w.Bytes()
					kv.rf.Snapshot(applyMsg.CommandIndex, kvstate)
				}
				kv.lastIncludedIndex = applyMsg.CommandIndex
			}
		} else if applyMsg.SnapshotValid {
			if applyMsg.SnapshotIndex <= kv.lastIncludedIndex {
				kv.mu.Unlock()
				continue
			}

			kv.readPersist(applyMsg.Snapshot)
			kv.lastIncludedIndex = applyMsg.SnapshotIndex
		}
		kv.mu.Unlock()
	}
}

实验结果

MIT6.5840-2023-Lab3B: Fault-tolerant K/V Service-Key/value service with snapshots_第2张图片

你可能感兴趣的:(Linux服务器编程,mit,raft,服务器,笔记,linux)