Etcd raft lib的snapshot處理流程
snapshot的是系統(tǒng)狀態(tài)的完整快照拉讯,其他系統(tǒng)接收和回放snapshot涤浇,將自身數(shù)據(jù)恢復到一個一致性狀態(tài)。本文介紹一下etcd raft lib如何支持snapshot功能魔慷,主要包括:
- 生成snapshot
- Leader發(fā)送snapshot
- Follower接收和應用snapshot
1.數(shù)據(jù)結構
type ConfState struct {
Nodes []uint64 `protobuf:"varint,1,rep,name=nodes" json:"nodes,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
type SnapshotMetadata struct {
ConfState ConfState `protobuf:"bytes,1,opt,name=conf_state,json=confState" json:"conf_state"`
Index uint64 `protobuf:"varint,2,opt,name=index" json:"index"`
Term uint64 `protobuf:"varint,3,opt,name=term" json:"term"`
XXX_unrecognized []byte `json:"-"`
}
type Snapshot struct {
Data []byte `protobuf:"bytes,1,opt,name=data" json:"data,omitempty"`
Metadata SnapshotMetadata `protobuf:"bytes,2,opt,name=metadata" json:"metadata"`
XXX_unrecognized []byte `json:"-"`
}
2.生成snapshot
etcd會在每次apply entry的時候循签,判斷是否需要生成snapshot帜篇。判斷的條件就是apply raft index 和上一個snapshot 中的index差距是否超過一定范圍。如果超過逞壁,則觸發(fā)snapshot服務故痊。具體函數(shù)流程如下圖所示:
由于etcd的snapshot生成和VDL生成snapshot不一樣萤彩,這里就不做詳細分析稳吮。
3.Leader發(fā)送snapshot
Leader在stepLeader函數(shù)中吉挣,會根據(jù)Follower的Next值向該Follower發(fā)送raft log。如果Leader上raft entry不存在隧熙,則會發(fā)送snapshot給follower。詳細的函數(shù)調用流程如下圖所示:
各個函數(shù)作用如下:
- sendAppend:Leader根據(jù)Follower的進度發(fā)送raft log幻林。
- r.raftLog.snapshot:調用存儲引擎贞盯,獲取最新的snapshot。
- pr.becomeSnapshot:將該follower狀態(tài)修改為ProgressStateSnapshot沪饺,表示正在發(fā)送snapshot躏敢。
- send:將snapshot類型的message發(fā)送給follower。
- newReady:將snapshot類型的message封裝在一個Ready結構中整葡,最終raft狀態(tài)機會將Ready結構體交給應用來處理件余。
- raftNode.start:在應用的外圍循環(huán)中,會不斷處理raft狀態(tài)機傳遞出來的Ready結構體遭居,對于snapshot會在r.processMessages函數(shù)中做處理啼器。
- r.processMessages:將包含snapshot信息的message傳遞給msgSnapC。
- applyAll:該函數(shù)會接收msgSnapC中的消息俱萍,并調用transport發(fā)送snapshot端壳。
- transport.SendSnapshot:調用transport層發(fā)送snapshot。
- peer.sendSnap:調用對應的peer的發(fā)送snapshot函數(shù)枪蘑。
- snapshotSender.send:真正的snapshot發(fā)送操作损谦。
4.Follower接收和應用snapshot
Follower上對snapshot的處理主要分為接收和應用snapshot兩個部分岖免,http包會創(chuàng)建一個goroutine來專門接收snapshot。接收完成后照捡,會將消息傳入raft狀態(tài)機颅湘,然后通過消息類型來驅動狀態(tài)機。具體的函數(shù)調用流程如下所示:
[圖片上傳失敗...(image-58cdb1-1522286696016)]
上述主要函數(shù)作用如下所示:
- snapshotHandler.ServeHTTP:snapshot的handler會一直等待接收snapshot栗精,如果收到snapshot會將其寫到磁盤闯参。
- snapshotter.SaveDBFrom:將收到snapshot會寫到磁盤
- Process:將收到snapshot的消息發(fā)送到raft 狀態(tài)機
- stepFollower:Follower收到MsgSnap消息后進入該函數(shù)。
- handleSnapshot:snapshot對應的消息類型是:MsgSnap术羔,會調用handleSnapshot赢赊。
- r.restore:清空unstable中的entries,并將snapshot保存到unstable中级历。
- newReady:根據(jù)unstable中的snapshot設置Ready結構體释移。
- raftNode.start:將snapshot發(fā)送到applyAll對應的goroutine
- applyAll:調用applySnapshot
- applySnapshot:etcd中應用snapshot的過程。