準備工作
1、閱讀raft論文
2、閱讀raft理論與實踐[1]-理論篇
3、閱讀raft理論與實踐[2]-lab2a
4、閱讀raft理論與實踐[3]-lab2a講解
5、閱讀raft理論與實踐[4]-lab2b日誌複製
6、查看我寫的這篇文章: 模擬RPC遠程過程調用
持久化
如果基於Raft的服務器重新啓動,則應從中斷的位置恢復服務。 這就要求Raft保持持久狀態,使其在重啓後仍然有效。
論文中Figure 2指出了那些字段需要持久化。
並且raft.go包含有關如何保存和恢復持久性狀態的示例。
一個“真實的服務在每次Raft更改狀態時將Raft的持久狀態寫入磁盤,並在重新啓動時從磁盤讀取最新的狀態來恢復。
但是我們的實現將會採用一個結構體的方式來模擬實現persister.go。
調用Raft.Make()會提供一個Persister,它持有Raft的最近持久狀態。
Raft應從該Persister初始化其狀態,並在每次狀態更改時修改其持久狀態。
主要使用Persister的ReadRaftState()和SaveRaftState()方法。
在本實驗中,我們需要完善在raft.go中的persist() and readPersist()方法。
需要使用到labgob包中的編碼與解碼函數。
你需要明確在什麼時候需要持久化。
下面只列出兩個重要實現,其他不再贅述,留給讀者自己實現。
持久化編碼
func (rf *Raft) persist() { // Your code here (2C). w := new(bytes.Buffer) e:= labgob.NewEncoder(w) e.Encode(rf.CurrentTerm) e.Encode(rf.VotedFor) e.Encode(rf.Logs) data := w.Bytes() rf.persister.SaveRaftState(data) }
持久化解碼
func (rf *Raft) readPersist(data []byte) { if data == nil || len(data) < 1 { // bootstrap without any state? return } // Your code here (2C). r := bytes.NewBuffer(data) d:= labgob.NewDecoder(r) d.Decode(&rf.CurrentTerm) d.Decode(&rf.VotedFor) d.Decode(&rf.Logs) }
測試
> go test -v -run=2C
參考資料
https://github.com/dreamerjackson/golang-deep-distributed-lab