DAY0: ETCD 架構
下圖中展示了 etcd 如何處理一個客戶端請求涉及到的模塊和流程。圖中淡紫色的矩陣表示 etcd ,它包括如下幾個模塊:

etcd server:
對外接受客戶端的請求,請求 etcd 代碼中的 etcd server 目錄,其中還有一個 raft.go 的模塊與 etcd raft 庫進行通信。etcd server 中與存儲相關的模塊是 applierV3,這里封裝了 V3 版本的數(shù)據(jù)存儲, WAL(write ahead log),用于寫數(shù)據(jù)日志,etcd 啟動時會根據(jù)這部分內(nèi)容進行恢復etcd raft:
etcd 的 raft 庫,前面的文章已經(jīng)具體分析過這部分代碼。除了與本節(jié)點的 etcd server 通信之外,還與集群中的其他 etcd server 進行交互一致性數(shù)據(jù)同步的工作(集群中其他etcd服務用橙色的橢圓表示)。
一個請求與一個 etcd 集群的交互主要流程分為兩大部分:
寫數(shù)據(jù)到某個 etcd server 中。
該 etcd server 與集群中的其他 etcd 節(jié)點進行交互, 當確保數(shù)據(jù)已經(jīng)被存儲之后應答客戶端。
請求流程劃分為了以下幾個子步驟:
- etcd server 收到客戶端請求。
- etcd server 將請求發(fā)送給本模塊的 raft.go,這里負責與 etcd raft 模塊進行通信。
- raft.go 將數(shù)據(jù)封裝成 raft 日志的形式提交給 raft 模塊。
- raft 模塊會首先保存到 raftLog 的 unstable 存儲部分。
- raft 模塊通過 raft 協(xié)議與集群中其他 etcd 節(jié)點進行交互。
應答步驟如下:
- 集群中其他節(jié)點向 leader 節(jié)點應答接收這條數(shù)據(jù)庫。
- 當 leader 節(jié)點收到超過半數(shù)以上應答接收這條日志數(shù)據(jù)的節(jié)點時,etcd raft 通過 Ready 結構體通知 etcd server 中的 raft 該日志數(shù)據(jù)已經(jīng) commit。
- raft.go 收到 Ready 數(shù)據(jù)時,首先將這條日志寫到 WAL 模塊中。
- 通知最上層的 etcd server 該日志已經(jīng) commit。
- etcd server 調(diào)用 applierV3 模塊將日志寫入持久化存儲中。
- etcd server 應答客戶端該數(shù)據(jù)寫入成功。
- 最后 etcd server 調(diào)用 etcd raft,修改其 raftLog 模塊的數(shù)據(jù),將這條日志寫入 raftLog storage 中。
從上面的流程可以看到:
etcd raft 模塊在應答某條日志數(shù)據(jù)已經(jīng) commit 之后,是首先寫入到 WAL 模塊中的,因為這個模塊只是添加一條日志,所以速度很快。即使在后面 applierV3 寫入失敗,重啟的時候也可以根據(jù) WAL 模塊中的日志數(shù)據(jù)進行恢復。
etcd raft 中的 raftLog,按照前面文章的分析,其中的數(shù)據(jù)是保存到內(nèi)存的,重啟即失效,上層應用真實的數(shù)據(jù)是持久化保存到 WAL 和 applierV3 中的。
主要模塊分析

- 用于與客戶端交互和底層 raft 模塊通信的 etcd-server
- 用于與集群中其他 etcd 節(jié)點通信的 etcd-raft
- 選主
- 用于存儲日志的 etcd-WAL
- 用于與客戶端交互的 etcd-client
- 用于持久化用戶數(shù)據(jù)的 etcd-storage
- 用于模塊通信之間的網(wǎng)絡協(xié)議
- 復制狀態(tài)機
- 持久存儲K-V數(shù)據(jù)庫