在任何一個系統中,甚麼東西會是最重要的東西呢?答案其實很簡單 : 資料,所以我就從 Kubernetes 的資料庫 etcd 開始學習起!
什麼是 etcd 呢
etcd 是 CoreOs 基於 Raft 算法開發的分散式 key-value 儲存,可用於服務發現、共享配置以及一致性保障 (如資料庫選主、分散式鎖等)。
在分散式系統中,如何管理節點間的狀態一直是個難題, etcd 像是專門為集群環境的服務發現和註冊而設計,它提供了資料 TTL 失效、資料改變監控、多值、目錄監聽、分散式鎖原子操作等功能,可以方便的跟蹤並管理集群節點的狀態。
etcd 特點
- 簡單 : curl 可訪問的用戶 API 。
- 安全 : 可選的 SSL 客戶端證書認證。
- 快速 : 單個實例每秒 1000 次寫操作, 2000+ 次讀操作。
- 可靠 : 使用 Raft 算法保證一致性。
etcd 名詞
- Raft : 強一致性的算法。
- Node : 一個 Raft State Machine 實例。
- Member : 一個 etcd 實例。它管理著一個 Node,並且可以為客戶端請求提供服務。
- Peer : 對同一個 etcd 集群中另外一個 Member 的稱呼。
- WAL : 預寫式日誌,etcd 用於持久化儲存的日誌格式。
- snapshot : etcd防止WAL文件過多而設置的快照,儲存 etcd 資料狀態。
- Proxy : etcd 的一種模式,為 etcd 集群提供反向代理服務。
- Leader : Raft 算法中通過競選而產生的處理所有資料提交的節點。
- Follower : 競選失敗的節點作為 Raft 中的附屬節點,為算法提供強一致性保證。
- Candidate : 當 Follower 超過一定時間接收不到 Leader 的心跳時轉變為 Candidate 並且開始競選 Leader。
- Term : 某個節點成為 Leader 到下一次競選時間,稱為一個 Term,可以理解為一個任期。
- Index : 資料編號。 Raft 中通過 Term 和 Index 來定位資料。
etcd 應用場景
Key Value 存儲
etcd 是一個基於 key value 儲存的資料庫,其他的應用都是基於 key value 的功能延展開來的。
- 採用 key value 的形式存儲,一般情況下會比關聯是資料庫來的快許多。
- 支援動態儲存 (RAM) 以及靜態儲存 (Disk)。
- 分散式儲存,可以集結成為多個 Nodes 的 Cluster。
- 儲存的方式類似於結構目錄 (B+tree)。
服務註冊與發現
- 強一致性、高可用的服務存儲目錄。
- 基於 Raft 算法的 etcd 天生就是這樣一個強一致性、高可用的服務存儲目錄。
- 一種註冊服務和服務健康狀況的機制。
- 用戶可以在 etcd 中註冊服務,並對註冊的服務配置 key TTL,定時保持服務的心跳以達到監控健康狀態的效果。
消息發布與訂閱
- 在分散式系統中,最適用的一種原件間通信方式就是消息發布與訂閱。
- 構建一個配置共享中心,資料提供者在這個配置中心發布消息,而消息使用者則訂閱他們關心的主題,一旦主題有消息發布,就會即時通知訂閱者。
- 通過這種方式可以做到分散式系統配置的集中式管理與動態更新。
- 應用中用到的一些配置信息放到 etcd 上進行集中管理。
- 應用在啟動的時候主動從 etcd 獲取一次配置信息,同時在etcd節點上註冊一個 Watcher 並等待,以後每次配置有更新的時候,etcd 都會即時通知訂閱者,以此達到獲取最新配置信息的目的。
etcd 架構
- HTTP Server : 提供 API ,並且提供資料讀寫功能,完成節點之間的通信。
- Raft : Raft 強一致性算法實現。
- Sotre : 用於處理 etcd 支持的各類功能的事務,包括資料索引、節點狀態變更、監控與反饋、事件處理與執行等等,是 etcd 對用戶提供的大多數 API 功能的具體實現。
- WAL : Write Ahead Log(預寫式日誌),是 etcd 的資料存儲方式。除了在內存中存有所有資料的狀態以及節點的索引以外,etcd 就通過 WAL 進行持久化存儲。 WAL 中,所有的資料提交前都會事先記錄日誌。
- Snapshot : 是為了防止資料過多而進行的狀態快照;
- Entry : 表示存儲的具體日誌內容。
etcd 基於 Raft 的一致性
Raft 協議是基於 quorum 機制,即大多數同意原則,任何得更變都需要超過半數的成員確認。
如果對於 Raft 不了解的話 ,可以參考一下 http://thesecretlivesofdata.com/raft/ 。
選舉方法
- 初始啟動時,節點處於 Follower 狀態並且會被設定一個 election timeout ,如果在這一個時間周期內妹有收到 Leader 的 heartbeat ,節點將會發起選舉,將自己切換為 candidate 之後,並向集群中其他 Follower 節點發送,詢問其是否選舉自己為 Leader 。
- 當收到來自集群中超過半數節點的接受頭票後,節點成為 Leader ,開始接收保存 client 的數據,並向其他的 Follower 節點同步日誌。如果沒有達成一致,則 candidate 隨機選擇等待間隔 (150ms ~ 300ms) 再次發起投票,得到集群中的半數以上 Follower 接受的 candidate 將成為 Leader 。
- Leader 節點依靠定時向 Follower 發送 heartbeat 來保持其地位。
- 任何時候如果其他 Follower 在 election timeout 期間都沒有收到來自 Leader 的 heartbeat,同樣會將自己的狀態切換為 candidate 並發起選舉。每成功選舉一次,新 Leader 的任期 (Term) 都會比之前 Leader 的任期大 1。
日誌複製
當 Leader 接收到客戶端的日誌 (事務請求) 後,先把該日誌追加到本地的 Log 中,然後通過 heartbeat 把該 Entry 同步給其他的 Follower, Follower 接收到日誌後記錄日誌,然後向 Leader 發送 ACK , 當 Leader 收到大多數 (n/2+1) 的 Follower ACK 後,將日誌設為已提交,並追加到本地瓷盤中,通知客戶端並在下一個 heartbeat 中 Leader 將通知所以的 Follower 將該日誌存儲在自己的硬碟中。
安全性
- 安全性 : 是用於保證每個節點都執行相同序列的安全機制。 如果當某個 Follower 在當前 Leader commit Log 時,變得不可用了,稍後可能該 Follower 又會被選舉為 Leader,這時新 Leader 可能會用新的 Log 覆蓋先前已 committed 的 Log,這就會導致節點執行不同序列。Safety 就是用於保證選舉出來的 Leader 一定會包含先前 commited Log 的機制。
- 選舉安全性 (Election Safety) : 每個任期 (Term) 只選出一個 Leader。
- Leader 完整性 (Leader Completeness) : 指 Leader 日誌的完整性,當 Log 在任期 Term1 被 commit 後,那麼以後的任期,Leader 都必須包含該 Log ,Raft 在選舉階段就使用 Term 的判斷用於保證完整性,當請求投票的該 Candidate 的 Term 較大或 Term 相同 Index 較大則投票,否則拒絕該請求。
wal 日誌 (write ahead log)
- wal 日誌是二進位,解析出來後是以上數據結構 LogEntry。
- 第一個 field 是 type , 0 表示Normal , 1 表示 ConfChange,意思是 etcd 本身的配置變更同步,譬如有新的節點加入。
- term , 每個 term 代表一個 Leader 的任期,每次 Leader 變更, term 就會加一。
- index,這個序號是嚴格有序的遞增的,代表變更序號。
- 二進位 data,將 raft request 對象 pb 結構整個保存下來。
- etcd 原始碼下面有個 tools/etcd-dump-logs ,可以將 wal 日誌 dump 成文本查看,可以協助分析 Raft 協議。
- Raft 協議本身並不關心應用數據,也就是 data 的部分,一致性都通過同步 wal 日誌來實現,每個節點將從 Leader 收到的 data apply 到本地的存儲, Raft 只關心日誌同步的狀況,如果本地存儲有 bug,有可能會導致數據不一致。
總結
終於對 kubernetes 核心之一的原件有了初步的認識,接下來會陸陸續續分享核心的原件給大家的。
歡迎到我的 Facebook Alan 的筆記本 留言,順手給我個讚吧!你的讚將成為我持續更新的動力,感謝你的閱讀,讓我們一起學習成為更好的自己。