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朋友圈,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/501216.html
標籤:其它
上一篇:mysql進階
下一篇:Redis 定長佇列的探索和實踐
