Etcd源碼分析之一:server啟動
這段時間看了比較久的etcd源碼,開始做總結。這個系列主要分析的是其中的一個etcd的example,代碼分支為:release-3.1, 路徑為:contrib/raftexample.
- 主流程啟動
L2-6解析啟動時傳入的命令行參數,cluster為節點間的通信地址,id為節點id, kvport為對外提供服務的埠,join為false時表示,這是一個新建的集群。
L8新建了一個proposeC, L9新建了一個confChangeC, 前者是kvstore結構體中的一個channel, 後者是httpHandler的一個channel. 在啟動http server之後,當收到Put
請求時,向proposeC中發送k-v消息;當收到POST
請求時,會向confChangeC中發送增加節點的消息,而當收到DELETE
請求時,會向confChangeC中發送刪除節點的消息。
L15定義獲取Snapshot的方法,L16新建了一個RaftNode, 返回一個已提交信息的channel, 一個錯誤信息的channel. 兩者都是非阻塞的channel. 以及一個容量為1的快照channel. RaftNode會消費confChangeC及proposeC里的消息,並作出相應的反應。
L18新建了kvstore, 它向proposeC中發送消息,從commitC中消費消息。
L21會啟動http服務。處理用戶的各種請求,包括set/get value, 及集群節點的變更請求等。
源碼中給出的一個啟動樣例如下:
在本地執行這三條命令,啟動了3個etcd服務進程,通過埠來區分它們。
最後,初步形成的整體架構如下圖,後續會繼續完善。
- RaftNode啟動
函數newRaftNode中,首先新建一個RaftNode, 將各種變數初始化好,然後調用startRaft()方法啟動。我們將這個函數分成四部分來看。
第一部分,L2-12 重放wal日誌
根據snapshot文件及wal日誌文件,將伺服器狀態恢復到上次停止時的狀態。
第二部分,L14-39啟動node,處理raft相關事務
創建node, 處理raft相關事務。
第三部分,L41-56 啟動transport, 建立和其他節點的通信通道
主動去向其他peer節點發送http請求。
第四部分,L59-60啟動監聽協程
serveRaft()監聽創建時的埠,用於和其他節點進行通信。第三部分節點會向其他節點發送請求。
serveChannels()會一直監聽proposeC和confChangeC, 獲取到消息後,調用node的Propose和ProposeConfChange方法進行處理。同時,啟動一個定時器,每100ms觸發一次node的tick. 當有日誌追加的時候,會將日誌追加到wal日誌,同時發送nil到commit通道,觸發kvstore將已經提交的日誌應用到狀態機中。
至此,etcd server已經啟動完畢。
推薦閱讀:
※從Chrome源碼看audio/video流媒體實現一
※LevelDB源碼解析4. 架構設計
※Spark源碼剖析(三):Executor啟動流程
※Flink CEP實現源碼解析