Docker學習系列 之etcd(一)etcd簡介

Etcd 按照官方介紹

Etcd is a distributed, consistent key-value store for shared configuration and service discovery

etcd 是一個分佈式一致性鍵值存儲,用於共享配置和服務發現,專注於:

簡單: 良好定義的,面向用戶的API (gRPC)
安全: 帶有可選客戶端證書認證的自動 TLS
快速: 測試驗證,每秒 10000 寫入
可靠: 使用Raft適當分佈

etcd是Go編寫,並使用 Raft 一致性算法來管理高可用複製日誌。


爲什麼需要 Etcd 

所有的分佈式系統,都面臨的一個問題是多個節點之間的數據共享問題,這個和團隊協作的道理是一樣的,成員可以分頭幹活,但總是需要共享一些必須的信息,比如誰是 leader, 都有哪些成員,依賴任務之間的順序協調等。所以分佈式系統要麼自己實現一個可靠的共享存儲來同步信息(比如 Elasticsearch ),要麼依賴一個可靠的共享存儲服務,而 Etcd 就是這樣一個服務。


Etcd 提供什麼能力

Etcd 主要提供以下能力,已經熟悉 Etcd 的讀者可以略過本段。

  1. 提供存儲以及獲取數據的接口,它通過協議保證 Etcd 集羣中的多個節點數據的強一致性。用於存儲元信息以及共享配置。

  2. 提供監聽機制,客戶端可以監聽某個key或者某些key的變更。用於監聽和推送變更。

  3. 提供key的過期以及續約機制,客戶端通過定時刷新來實現續約。用於集羣監控以及服務註冊發現。

  4. 提供原子的CAS(Compare-and-Swap)和 CAD(Compare-and-Delete)支持(v2通過接口參數實現,v3通過批量事務實現)。用於分佈式鎖以及leader選舉。


Etcd 如何實現一致性的

Etcd使用Raft協議來維護集羣內各個節點狀態的一致性。簡單說,Etcd集羣是一個分佈式系統,由多個節點相互通信構成整體對外服務,每個節點都存儲了完整的數據,並且通過Raft協議保證每個節點維護的數據是一致的。

DraggedImage_1
如圖所示,每個Etcd節點都維護了一個狀態機,並且,任意時刻至多存在一個有效的主節點。主節點處理所有來自客戶端寫操作,通過Raft協議保證寫操作對狀態機的改動會可靠的同步到其他節點。

Etcd工作原理核心部分在於Raft協議。本節接下來將簡要介紹Raft協議,具體細節請參考其[論文]。
Raft協議正如論文所述,確實方便理解。主要分爲三個部分:選主,日誌複製,安全性。


1) 選主

Raft協議是用於維護一組服務節點數據一致性的協議。這一組服務節點構成一個集羣,並且有一個主節點來對外提供服務。當集羣初始化,或者主節點掛掉後,面臨一個選主問題。集羣中每個節點,任意時刻處於Leader, Follower, Candidate這三個角色之一。選舉特點如下:

  • 當集羣初始化時候,每個節點都是Follower角色;

  • 集羣中存在至多1個有效的主節點,通過心跳與其他節點同步數據;

  • 當Follower在一定時間內沒有收到來自主節點的心跳,會將自己角色改變爲Candidate,併發起一次選主投票;當收到包括自己在內超過半數節點贊成後,選舉成功;當收到票數不足半數選舉失敗,或者選舉超時。若本輪未選出主節點,將進行下一輪選舉(出現這種情況,是由於多個節點同時選舉,所有節點均爲獲得過半選票)。

  • Candidate節點收到來自主節點的信息後,會立即終止選舉過程,進入Follower角色。

    爲了避免陷入選主失敗循環,每個節點未收到心跳發起選舉的時間是一定範圍內的隨機值,這樣能夠避免2個節點同時發起選主。

2) 日誌複製

所謂日誌複製,是指主節點將每次操作形成日誌條目,並持久化到本地磁盤,然後通過網絡IO發送給其他節點。其他節點根據日誌的邏輯時鐘(TERM)和日誌編號(INDEX)來判斷是否將該日誌記錄持久化到本地。當主節點收到包括自己在內超過半數節點成功返回,那麼認爲該日誌是可提交的(committed),並將日誌輸入到狀態機,將結果返回給客戶端。

這裏需要注意的是,每次選主都會形成一個唯一的TERM編號,相當於邏輯時鐘。每一條日誌都有全局唯一的編號。

DraggedImage_2

主節點通過網絡IO向其他節點追加日誌。若某節點收到日誌追加的消息,首先判斷該日誌的TERM是否過期,以及該日誌條目的INDEX是否比當前以及提交的日誌的INDEX跟早。若已過期,或者比提交的日誌更早,那麼就拒絕追加,並返回該節點當前的已提交的日誌的編號。否則,將日誌追加,並返回成功。

當主節點收到其他節點關於日誌追加的回覆後,若發現有拒絕,則根據該節點返回的已提交日誌編號,發生其編號下一條日誌。

主節點像其他節點同步日誌,還作了擁塞控制。具體地說,主節點發現日誌複製的目標節點拒絕了某次日誌追加消息,將進入日誌探測階段,一條一條發送日誌,直到目標節點接受日誌,然後進入快速複製階段,可進行批量日誌追加。

按照日誌複製的邏輯,我們可以看到,集羣中慢節點不影響整個集羣的性能。另外一個特點是,數據只從主節點複製到Follower節點,這樣大大簡化了邏輯流程。


3) 安全性

截止此刻,選主以及日誌複製並不能保證節點間數據一致。試想,當一個某個節點掛掉了,一段時間後再次重啓,並當選爲主節點。而在其掛掉這段時間內,集羣若有超過半數節點存活,集羣會正常工作,那麼會有日誌提交。這些提交的日誌無法傳遞給掛掉的節點。當掛掉的節點再次當選主節點,它將缺失部分已提交的日誌。在這樣場景下,按Raft協議,它將自己日誌複製給其他節點,會將集羣已經提交的日誌給覆蓋掉。

這顯然是不可接受的。

其他協議解決這個問題的辦法是,新當選的主節點會詢問其他節點,和自己數據對比,確定出集羣已提交數據,然後將缺失的數據同步過來。這個方案有明顯缺陷,增加了集羣恢復服務的時間(集羣在選舉階段不可服務),並且增加了協議的複雜度。

Raft解決的辦法是,在選主邏輯中,對能夠成爲主的節點加以限制,確保選出的節點已定包含了集羣已經提交的所有日誌。如果新選出的主節點已經包含了集羣所有提交的日誌,那就不需要從和其他節點比對數據了。簡化了流程,縮短了集羣恢復服務的時間。

這裏存在一個問題,加以這樣限制之後,還能否選出主呢?答案是:只要仍然有超過半數節點存活,這樣的主一定能夠選出。因爲已經提交的日誌必然被集羣中超過半數節點持久化,顯然前一個主節點提交的最後一條日誌也被集羣中大部分節點持久化。當主節點掛掉後,集羣中仍有大部分節點存活,那這存活的節點中一定存在一個節點包含了已經提交的日誌了。

至此,關於Raft協議的簡介就全部結束了。


Etcd的使用場景

和ZK類似,Etcd有很多使用場景,包括:

  • 配置管理

  • 服務註冊於發現

  • 選主

  • 應用調度

  • 分佈式隊列

  • 分佈式鎖

Etcd,Zookeeper,Consul 比較

這三個產品是經常被人拿來做選型比較的。 Etcd 和 Zookeeper 提供的能力非常相似,都是通用的一致性元信息存儲,都提供watch機制用於變更通知和分發,也都被分佈式系統用來作爲共享信息存儲,在軟件生態中所處的位置也幾乎是一樣的,可以互相替代的。二者除了實現細節,語言,一致性協議上的區別,最大的區別在周邊生態圈。Zookeeper 是apache下的,用java寫的,提供rpc接口,最早從hadoop項目中孵化出來,在分佈式系統中得到廣泛使用(hadoop, solr, kafka, mesos 等)。Etcd 是coreos公司旗下的開源產品,比較新,以其簡單好用的rest接口以及活躍的社區俘獲了一批用戶,在新的一些集羣中得到使用(比如kubernetes)。雖然v3爲了性能也改成二進制rpc接口了,但其易用性上比 Zookeeper 還是好一些。 而 Consul 的目標則更爲具體一些,Etcd 和 Zookeeper 提供的是分佈式一致性存儲能力,具體的業務場景需要用戶自己實現,比如服務發現,比如配置變更。而Consul 則以服務發現和配置變更爲主要目標,同時附帶了kv存儲。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章