1.ETCD概述 1.1 ETCD概述 etcd是一個高可用的分散式的鍵值對存儲系統,常用做配置共用和服務發現。由CoreOS公司發起的一個開源項目,受到ZooKeeper與doozer啟發而催生的項目,名稱etcd源自兩個想法,即Linux的**/etc文件夾和d分散式系統。/etc**文件夾是用 ...
1.ETCD概述
1.1 ETCD概述
etcd是一個高可用的分散式的鍵值對存儲系統,常用做配置共用和服務發現。由CoreOS公司發起的一個開源項目,受到ZooKeeper與doozer啟發而催生的項目,名稱etcd源自兩個想法,即Linux的/etc文件夾和d分散式系統。/etc文件夾是用於存儲單個系統的配置數據的地方,而etcd用於存儲大規模分散式的配置信息,具有以下特點:
- 簡單:基於HTTP+JSON的API,用curl就可以輕鬆使用
- 可信:使用Raft演算法充分實現了分散式
- 安全:可選SSL客戶認證機制
- 快速:每個節點可支持上萬QPS讀寫
etcd有V2和V3兩個版本,二者不相容,目前使用比較廣泛的是V3版本
1.2 ETCD工作原理
etcd集群本身是一個分散式系統,由多個節點相互通信構成整體對外服務,每個節點都存儲了完整的數據,並且通過Raft協議保證每個節點維護的數據是一致的,在ETCD集群中任意時刻最多存在一個有效的主節點,由主節點處理所有來自客戶端寫操作,通過Raft協議保證寫操作對狀態機的改動會可靠的同步到其他節點,Raft協議如下所示:
Raft協議主要分為三個部分:選舉,複製日誌,安全性
1.2.1 選舉
Raft協議是用於維護一組服務節點數據一致性的協議。這一組服務節點構成一個集群,並且有一個主節點來對外提供服務。當集群初始化,或者主節點掛掉後,面臨一個選舉問題。集群中每個節點,任意時刻處於Leader(領導者)、Follower(追隨者)、Candidate(候選者)這三個角色之一,選舉特點如下:
- 當集群初始化時候,每個節點都是Follower角色
- 集群中存在最多1個有效的主節點,通過心跳與其他節點同步數據
- 當Follower在一定時間內沒有收到來自主節點的心跳,會將自己角色改變為Candidate,併發起一次選舉投票
- 當收到包括自己在內超過半數節點贊成後,選舉成功
- 當收到票數不足半數選舉失敗,或者選舉超時
- 若本輪未選出主節點,將進行下一輪選舉(出現這種情況,是由於多個節點同時選舉,所有節點均為獲得過半選票) - Candidate節點收到來自主節點的信息後,會立即終止選舉過程,進入Follower角色
為了避免陷入選舉失敗迴圈,每個節點未收到心跳發起選舉的時間是一定範圍內的隨機值,這樣能夠避免2個節點同時發起選舉。
示意圖如下所示:
1.2.2 複製日誌
日誌複製是指主節點將每次操作形成日誌條目,並持久化到本地磁碟,然後通過網路IO發送給其他節點。其他節點根據日誌的邏輯時鐘(TERM)和日誌編號(INDEX)來判斷是否將該日誌記錄持久化到本地。當主節點收到包括自己在內超過半數節點成功返回,那麼認為該日誌是可提交的(committed),並將日誌輸入到狀態機,將結果返回給客戶端。
這裡需要註意的是,每次選舉都會形成一個唯一的TERM編號,相當於邏輯時鐘,每一條日誌都有全局唯一的編號
主節點通過網路IO向其他節點追加日誌。若某節點收到日誌追加的消息,首先判斷該日誌的TERM是否過期,以及該日誌條目的INDEX是否比當前以及提交的日誌的INDEX跟早。若已過期,或者比提交的日誌更早,那麼就拒絕追加,並返回該節點當前的已提交的日誌的編號。否則將日誌追加,並返回成功。
當主節點收到其他節點關於日誌追加的回覆後,若發現有拒絕,則根據該節點返回的已提交日誌編號,發送其編號下一條日誌
主節點向其他節點同步日誌,還作了擁塞控制。主節點發現日誌複製的目標節點拒絕了某次日誌追加消息,將進入日誌探測階段,一條一條發送日誌,直到目標節點接受日誌,然後進入快速複製階段,可進行批量日誌追加。
按照日誌複製的邏輯,我們可以看到,集群中慢節點不影響整個集群的性能。另外一個特點是,數據只從主節點複製到Follower節點,這樣大大簡化了邏輯流程。Raft日誌複製路程如下圖所示:
1.2.3 安全
選舉和複製日誌並不能保證節點間數據一致。當一個某個節點掛掉了,一段時間後再次重啟,並剛好當選為主節點。而在其掛掉這段時間內,集群若有超過半數節點存活,集群會正常工作,那麼會有日誌提交,這些提交的日誌無法傳遞給掛掉的節點。當掛掉的節點再次當選舉節點,它將缺失部分已提交的日誌。在這樣場景下,按Raft協議,它將自己日誌複製給其他節點,會將集群已經提交的日誌給覆蓋掉,這顯然是不可接受的,對於出現這種問題解決辦法:
- 其他協議解決這個問題的辦法是,新當選的主節點會詢問其他節點,和自己數據對比,確定出集群已提交數據,然後將缺失的數據同步過來。這個方案有明顯缺陷,增加了集群恢復服務的時間(集群在選舉階段不可服務),並且增加了協議的複雜度。
- Raft解決的辦法是,在選舉邏輯中,對能夠成為主節點加以限制,確保選出的節點已定包含了集群已經提交的所有日誌。如果新選出的主節點已經包含了集群所有提交的日誌,那就不需要從和其他節點比對數據了,簡化了流程,縮短了集群恢復服務的時間
為什麼只要仍然有超過半數節點存活,一定能夠選出包含所有日誌數據的節點作為主節點呢?因為已經提交的日誌必然被集群中超過半數節點持久化,顯然前一個主節點提交的最後一條日誌也被集群中大部分節點持久化。當主節點掛掉後,集群中仍有大部分節點存活,那這存活的節點中一定存在一個節點包含了已經提交的日誌了,因此要求etcd集群節點數量為奇數(3,5,7,9……)
1.3 ETCD應用場景
ETCD服務發現示意圖如下圖所示:
服務發現是分散式系統中最常見的需要解決的問題之一,即在同一個分散式集群中的進程或服務,客戶端通過名字就可以查找和連接服務端。要解決服務發現的問題,需要有下麵三點:
- 一個強一致性、高可用的服務存儲目錄。基於Raft演算法的etcd天生就是這樣一個強一致性高可用的服務存儲目錄
- 一種註冊服務和監控服務健康狀態的機制。用戶可以在etcd中註冊服務,並且對註冊的服務設置key TTL,定時保持服務的心跳以達到監控健康狀態的效果
- 一種查找和連接服務的機制。通過在etcd指定的主題快速找到服務地址
1.3.1 服務發現
1.3.1.1 在微服務中使用etcd服務發現
隨著Docker容器的流行,多種微服務共同協作,構成一個相對功能強大的組織架構。使用etcd服務發現機制,在etcd中註冊某個服務名字的目錄,在該目錄下存儲可用的服務節點的IP。服務使用者從etcd目錄下查找可用的服務節點IP來連接和調用,達到透明化的動態添加這些服務目的,示意圖如下圖所示:
1.3.1.2 在PaaS平臺中使用etcd服務發現
PaaS平臺中的應用一般都有多個實例,通過功能變數名稱不僅可以透明的對多個實例進行訪問,而且還可以做到負載均衡。但是應用的某個實例隨時都有可能故障重啟,這時就需要動態的配置功能變數名稱解析(路由)信息,通過etcd的服務發現功能就可以輕鬆解決這個動態配置的問題,實現多實例與實例故障重啟透明化目的,示意圖如下圖所示:
1.3.2 發佈訂閱消息
etcd的發佈訂閱消息示意圖如下圖所示:
在分散式系統中,消息發佈與訂閱最適合使用在組件之間通信。使用etcd發佈訂閱功能可以實現一個配置共用中心,數據提供者在配置中心發佈消息,消息消費者訂閱他們關心的主題,一旦主題有新消息發佈,就會實時通知訂閱者,通過這種方式可以做到分散式系統配置的集中式管理與動態更新。
etcd發佈訂閱最典型應用在kubernetes上,其他場景應用:
- app或服務用到的一些配置信息放到etcd上進行集中管理。在啟動的時候主動從etcd獲取一次配置信息,在etcd節點上註冊一個Watcher並等待,以後每次配置有更新的時候,etcd都會實時通知訂閱者,以此達到獲取最新配置信息的目的。
- 分散式搜索服務中,索引的元信息和伺服器集群機器的節點狀態存放在etcd中,供各個客戶端訂閱使用。使用etcd的key TTL功能可以確保機器狀態是實時更新的。
- 分散式日誌收集系統。 這個系統的核心工作是收集分佈在不同機器的日誌。收集器通常是按照應用(或主題)來分配收集任務單元,因此可以在etcd上創建一個以應用(主題)命名的目錄,並將這個應用(主題相關)的所有機器ip,以子目錄的形式存儲到目錄上,然後設置一個etcd遞歸的Watcher,遞歸式的監控應用(主題)目錄下所有信息的變動。這樣就實現了機器IP(消息)變動的時候,能夠實時通知到收集器調整任務分配
- 系統中信息需要動態自動獲取與人工干預修改信息請求內容的情況。只需要要將信息存放到指定的etcd目錄中,etcd的這些目錄就可以通過HTTP的介面在外部訪問
1.3.3 負載均衡
etcd的負載均衡示意圖如下圖所示:
etcd本身分散式架構存儲的信息訪問支持負載均衡,etcd集群化以後,每個etcd的核心節點都可以處理用戶的請求。所以把數據量小但是訪問頻繁的消息數據直接存儲到etcd中也是個不錯的選擇。 etcd可以監控一個集群中多個節點的狀態,利用etcd維護一個負載均衡節點表,當有一個請求發過來後,可以輪詢式的把請求轉發給存活著的節點。
分散式系統中,為了保證服務的高可用以及數據的一致性,通常都會把數據和服務部署多份,以此達到對等服務,即使其中的某一個服務失效了,也不影響使用。由此帶來的壞處是數據寫入性能下降,而好處則是數據訪問時的負載均衡。因為每個對等服務節點上都存有完整的數據,所以用戶的訪問流量就可以分流到不同的機器上。
1.3.4 分散式通知與協調
分散式通知與協調,與消息發佈和訂閱有些相似。都用到了etcd中Watche機制,通過註冊與非同步通知機制,實現分散式環境下不同系統之間 的通知與協調,從而對數據變更做到實時處理。實現方式:不同系統都在etcd上對同一個目錄進行註冊,同時設置Watcher觀測該目錄的變化(如果對子目錄的變化也有需要,可以設置遞歸模式),當某個系統更新了etcd的目錄,那麼設置了Watcher的系統就會收到通知,並作出相應處理。其工作原理如下所示:
- 通過etcd進行低耦合的心跳檢測:檢測系統和被檢測系統通過etcd上某個目錄關聯而非直接關聯起來,這樣可以大大減少系統的耦合性
- 通過etcd完成系統調度:某系統有控制台和推送系統兩部分組成,控制台的職責是控制推送系統進行相應的推送工作。管理人員在控制台作的一些操作,實際上是修改了etcd上某些目錄節點的狀態,而etcd就把這些變化通知給註冊了Watcher的推送系統客戶端,推送系統再作出相應的推送任務。
- 通過etcd完成工作彙報:大部分類似的任務分發系統,子任務啟動後,到etcd來註冊一個臨時工作目錄,並且定時將自己的進度進行彙報(將進度寫入到這個臨時目錄),這樣任務管理者就能夠實時知道任務進度
1.3.5 分散式鎖
因為etcd使用Raft演算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分散式鎖,鎖有兩種使用方式:
- 保持獨占:即所有獲取鎖的用戶最終只有一個可以得到
etcd為此提供了一套實現分散式鎖原子操作CAS(CompareAndSwap)的API。通過設置prevExist值,可以保證在多個節點同時去創建某個目錄時只有一個成功,而創建成功的用戶就可以認為是獲得了鎖。
- 控制時序:即所有想要獲得鎖的用戶都會被安排執行,但是獲得鎖的順序也是全局唯一的,同時決定了執行順序
etcd為此也提供了一套API(自動創建有序鍵),對一個目錄建值時指定為POST動作,這樣etcd會自動在目錄下生成一個當前最大的值為鍵,存儲這個新的值(客戶端編號)。同時還可以使用API按順序列出所有當前目錄下的鍵值。此時這些鍵的值就是客戶端的時序,而這些鍵中存儲的值可以是代表客戶端的編號。
示意圖如下所示:
1.3.6 分散式隊列
分散式隊列的常規用法與分散式鎖的控制時序用法類似,創建一個先進先出的隊列,保證順序。另一種比較有意思的實現是在保證隊列達到某個條件時再統一按順序執行。這種方法的實現可以在/queue這個目錄中另外建立一個/queue/condition節點,condition可以表示信息如下:
- condition可以表示隊列大小。比如一個大的任務需要很多小任務就緒的情況下才能執行,每次有一個小任務就緒,就給這個condition數字加1,直到達到大任務規定的數字,再開始執行隊列里的一系列小任務,最終執行大任務,如下圖所示:
-
condition可以表示某個任務在不在隊列。這個任務可以是所有排序任務的首個執行程式,也可以是拓撲結構中沒有依賴的點。通常必須執行這些任務後才能執行隊列中的其他任務。
-
condition還可以表示其它的一類開始執行任務的通知。可以由控製程序指定,當condition出現變化時,開始執行隊列任務。
1.3.7 集群監控
使用etcd來實現集群的實時性的監控,可以第一時間檢測到各節點的健康狀態,以完成集群的監控要求。etcd本身就有自帶檢點健康監控功能,實現起來也比較簡單
- 使用Watcher機制,當某個節點消失或有變動時,Watcher會第一時間發現並告知用戶
- 節點可以設置TTL key,比如每隔30s發送一次心跳使代表該機器存活的節點繼續存在,否則節點消失
1.3.8 Leader競選
使用分散式鎖,可以完成Leader競選。這種場景通常是一些長時間CPU計算或者使用IO操作的機器,只需要競選出的Leader計算或處理一次,就可以把結果複製給其他的Follower,從而避免重覆勞動,節省計算資源。
可使用在搜索系統中建立全量索引。如果每個機器都進行一遍索引的建立,不但耗時而且建立索引的一致性不能保證。通過在etcd的CAS機制同時創建一個節點,創建成功的機器作為Leader,進行索引計算,然後把計算結果分發到其它節點。
原文地址:https://www.jianshu.com/p/f1b731766d5a
本文同步在微信訂閱號上發佈,如各位小伙伴們喜歡我的文章,也可以關註我的微信訂閱號:woaitest,或掃描下麵的二維碼添加關註:
作者: Surpassme
來源: http://www.jianshu.com/u/28161b7c9995/
http://www.cnblogs.com/surpassme/
聲明:本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出 原文鏈接 ,否則保留追究法律責任的權利。如有問題,可發送郵件 聯繫。讓我們尊重原創者版權,共同營造良好的IT朋友圈。