etcd的應用場景

提到etcd很多人第一反應就是一個鍵值存儲倉庫。不過etcd官方文檔的定義卻是這樣的:

A highly-available key value store for shared configuration and service discovery.

包含了配置共享和服務發現。

etcd作為一個受到ZooKeeper與doozer啟發而催生的項目,除了擁有與之類似的功能外,更專注于以下四點。

  • 簡單:基于HTTP+JSON的API讓你用curl就可以輕松使用。
  • 安全:可選SSL客戶認證機制。
  • 快速:每個實例每秒支持一千次寫操作。
  • 可信:使用Raft算法充分實現了分布式。

接下來將針對剖析一些etcd的經典使用場景,來看看etcd這個基于Raft強一致性算法的分布式存儲倉庫能給我們帶來哪些幫助。

值得注意的是,分布式系統中的數據分為控制數據和應用數據。使用etcd的場景默認處理的數據都是控制數據,對于應用數據,只推薦數據量很小,但是更新訪問頻繁的情況。

場景一:服務發現(Service Discovery)

在分布式系統中“服務發現”也是比較常見的問題:在同一個集群環境中不同的應用或服務,如何能夠找到對方并建立連接,來完成后續的行為。本質上來說,服務發現就是想要知道集群中是否有進程在監聽udp或tcp端口,并能通過名字就可以查找和連接。而要解決服務發現的問題,需要滿足如下三個方面,缺一不可。

  1. 一個強一致性、高可用的服務存儲目錄: 基于Raft算法的etcd天生就是這樣一個強一致性高可用的服務存儲目錄【安全的記錄集群中的應用或服務的信息(地址、端口等)】。
  2. 一種注冊服務和監控服務健康狀態的機制:用戶可以在etcd中注冊服務,并且對注冊的服務設置key TTL,定時保持服務的心跳以達到監控健康狀態的效果。【能夠完成新的應用或服務的注冊添加進來,同樣也能對現有的服務是否可用進行監控】
  3. 一種查找和連接服務的機制: 通過在etcd指定的主題下注冊的服務也能在對應的主題下查找到。為了確保連接,我們可以在每個服務機器上都部署一個Proxy模式的etcd,這樣就可以確保能訪問etcd集群的服務都能互相連接。【已有的服務當被使用能夠被找到并能連接】
服務發現

來看服務發現對應的具體場景:

  • 微服務協同工作架構中,服務動態添加。隨著Docker容器的流行,多種微服務共同協作,構成一個相對功能強大的架構的案例越來越多。透明化的動態添加這些服務的需求也日益強烈。通過服務發現機制,在etcd中注冊某個服務名字的目錄,在該目錄下存儲可用的服務節點的IP。在使用服務的過程中,只要從服務目錄下查找可用的服務節點去使用即可。
微服務協同工作
  • PaaS平臺中應用多實例與實例故障重啟透明化。PaaS平臺中的應用一般都有多個實例,通過域名,不僅可以透明的對這多個實例進行訪問,而且還可以做到負載均衡。但是應用的某個實例隨時都有可能故障重啟,這時就需要動態的配置域名解析(路由)中的信息。通過etcd的服務發現功能就可以輕松解決這個動態配置的問題。
云平臺多實例透明化

場景二:消息發布與訂閱

在分布式系統中,最適用的一種組件間通信方式就是消息發布與訂閱。即構建一個配置共享中心,數據提供者在這個配置中心發布消息,而消息使用者則訂閱他們關心的主題,一旦主題有消息發布,就會實時通知訂閱者。通過這種方式可以做到分布式系統配置的集中式管理與動態更新。

  • 應用中用到的一些配置信息放到etcd上進行集中管理。這類場景的使用方式通常是這樣:應用在啟動的時候主動從etcd獲取一次配置信息,同時,在etcd節點上注冊一個Watcher并等待,以后每次配置有更新的時候,etcd都會實時通知訂閱者,以此達到獲取最新配置信息的目的。
  • 分布式搜索服務中,索引的元信息和服務器集群機器的節點狀態存放在etcd中,供各個客戶端訂閱使用。使用etcd的key TTL功能可以確保機器狀態是實時更新的。
  • 分布式日志收集系統。這個系統的核心工作是收集分布在不同機器的日志。收集器通常是按照應用(或主題)來分配收集任務單元,因此可以在etcd上創建一個以應用(主題)命名的目錄P,并將這個應用(主題相關)的所有機器ip,以子目錄的形式存儲到目錄P上,然后設置一個etcd遞歸的Watcher,遞歸式的監控應用(主題)目錄下所有信息的變動。這樣就實現了機器IP(消息)變動的時候,能夠實時通知到收集器調整任務分配。
  • 系統中信息需要動態自動獲取與人工干預修改信息請求內容的情況。通常是暴露出接口,例如JMX接口,來獲取一些運行時的信息。引入etcd之后,就不用自己實現一套方案了,只要將這些信息存放到指定的etcd目錄中即可,etcd的這些目錄就可以通過HTTP的接口在外部訪問。
消息發布與訂閱

場景三:負載均衡

在場景一中也提到了負載均衡,本文所指的負載均衡均為軟負載均衡。分布式系統中,為了保證服務的高可用以及數據的一致性,通常都會把數據和服務部署多份,以此達到對等服務,即使其中的某一個服務失效了,也不影響使用。由此帶來的壞處是數據寫入性能下降,而好處則是數據訪問時的負載均衡。因為每個對等服務節點上都存有完整的數據,所以用戶的訪問流量就可以分流到不同的機器上。

  • etcd本身分布式架構存儲的信息訪問支持負載均衡。etcd集群化以后,每個etcd的核心節點都可以處理用戶的請求。所以,把數據量小但是訪問頻繁的消息數據直接存儲到etcd中也是個不錯的選擇,如業務系統中常用的二級代碼表(在表中存儲代碼,在etcd中存儲代碼所代表的具體含義,業務系統調用查表的過程,就需要查找表中代碼的含義)。
  • 利用etcd維護一個負載均衡節點表。etcd可以監控一個集群中多個節點的狀態,當有一個請求發過來后,可以輪詢式的把請求轉發給存活著的多個狀態。類似KafkaMQ,通過ZooKeeper來維護生產者和消費者的負載均衡。同樣也可以用etcd來做ZooKeeper的工作。
負載均衡

場景四:分布式通知與協調

這里說到的分布式通知與協調,與消息發布和訂閱有些相似。都用到了etcd中的Watcher機制,通過注冊與異步通知機制,實現分布式環境下不同系統之間的通知與協調,從而對數據變更做到實時處理。實現方式通常是這樣:不同系統都在etcd上對同一個目錄進行注冊,同時設置Watcher觀測該目錄的變化(如果對子目錄的變化也有需要,可以設置遞歸模式),當某個系統更新了etcd的目錄,那么設置了Watcher的系統就會收到通知,并作出相應處理。

  • 通過etcd進行低耦合的心跳檢測。檢測系統和被檢測系統通過etcd上某個目錄關聯而非直接關聯起來,這樣可以大大減少系統的耦合性。
  • 通過etcd完成系統調度。某系統有控制臺和推送系統兩部分組成,控制臺的職責是控制推送系統進行相應的推送工作。管理人員在控制臺作的一些操作,實際上是修改了etcd上某些目錄節點的狀態,而etcd就把這些變化通知給注冊了Watcher的推送系統客戶端,推送系統再作出相應的推送任務。
  • 通過etcd完成工作匯報。大部分類似的任務分發系統,子任務啟動后,到etcd來注冊一個臨時工作目錄,并且定時將自己的進度進行匯報(將進度寫入到這個臨時目錄),這樣任務管理者就能夠實時知道任務進度。
分布式協同工作

場景五:分布式鎖

因為etcd使用Raft算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分布式鎖。鎖服務有兩種使用方式,一是保持獨占,二是控制時序。

  • 保持獨占即所有獲取鎖的用戶最終只有一個可以得到。etcd為此提供了一套實現分布式鎖原子操作CAS(CompareAndSwap)的API。通過設置prevExist值,可以保證在多個節點同時去創建某個目錄時,只有一個成功。而創建成功的用戶就可以認為是獲得了鎖。
  • 控制時序,即所有想要獲得鎖的用戶都會被安排執行,但是獲得鎖的順序也是全局唯一的,同時決定了執行順序。etcd為此也提供了一套API(自動創建有序鍵),對一個目錄建值時指定為POST動作,這樣etcd會自動在目錄下生成一個當前最大的值為鍵,存儲這個新的值(客戶端編號)。同時還可以使用API按順序列出所有當前目錄下的鍵值。此時這些鍵的值就是客戶端的時序,而這些鍵中存儲的值可以是代表客戶端的編號。
分布式鎖

場景六:分布式隊列

分布式隊列的常規用法與場景五中所描述的分布式鎖的控制時序用法類似,即創建一個先進先出的隊列,保證順序。

另一種比較有意思的實現是在保證隊列達到某個條件時再統一按順序執行。這種方法的實現可以在/queue這個目錄中另外建立一個/queue/condition節點。

  • condition可以表示隊列大小。比如一個大的任務需要很多小任務就緒的情況下才能執行,每次有一個小任務就緒,就給這個condition數字加1,直到達到大任務規定的數字,再開始執行隊列里的一系列小任務,最終執行大任務。
  • condition可以表示某個任務在不在隊列。這個任務可以是所有排序任務的首個執行程序,也可以是拓撲結構中沒有依賴的點。通常,必須執行這些任務后才能執行隊列中的其他任務。
  • condition還可以表示其它的一類開始執行任務的通知。可以由控制程序指定,當condition出現變化時,開始執行隊列任務。
分布式隊列

場景七:集群監控與Leader競選

通過etcd來進行監控實現起來非常簡單并且實時性強。

  1. 前面幾個場景已經提到Watcher機制,當某個節點消失或有變動時,Watcher會第一時間發現并告知用戶。
  2. 節點可以設置TTL key,比如每隔30s發送一次心跳使代表該機器存活的節點繼續存在,否則節點消失。

這樣就可以第一時間檢測到各節點的健康狀態,以完成集群的監控要求。

另外,使用分布式鎖,可以完成Leader競選。這種場景通常是一些長時間CPU計算或者使用IO操作的機器,只需要競選出的Leader計算或處理一次,就可以把結果復制給其他的Follower。從而避免重復勞動,節省計算資源。

這個的經典場景是搜索系統中建立全量索引。如果每個機器都進行一遍索引的建立,不但耗時而且建立索引的一致性不能保證。通過在etcd的CAS機制同時創建一個節點,創建成功的機器作為Leader,進行索引計算,然后把計算結果分發到其它節點。

Leader競選

場景八:為什么用etcd而不用ZooKeeper?

etcd實現的這些功能,ZooKeeper都能實現。那么為什么要用etcd而非直接使用ZooKeeper呢?

相較之下,ZooKeeper有如下缺點:

  1. 復雜。ZooKeeper的部署維護復雜,管理員需要掌握一系列的知識和技能;而Paxos強一致性算法也是素來以復雜難懂而聞名于世;另外,ZooKeeper的使用也比較復雜,需要安裝客戶端,官方只提供了Java和C兩種語言的接口。
  2. Java編寫。這里不是對Java有偏見,而是Java本身就偏向于重型應用,它會引入大量的依賴。而運維人員則普遍希望保持強一致、高可用的機器集群盡可能簡單,維護起來也不易出錯。
  3. 發展緩慢。Apache基金會項目特有的“Apache Way”在開源界飽受爭議,其中一大原因就是由于基金會龐大的結構以及松散的管理導致項目發展緩慢。

而etcd作為一個后起之秀,其優點也很明顯。

  1. 簡單。使用Go語言編寫部署簡單;使用HTTP作為接口使用簡單;使用Raft算法保證強一致性讓用戶易于理解。
  2. 數據持久化。etcd默認數據一更新就進行持久化。
  3. 安全。etcd支持SSL客戶端安全認證。

最后,etcd作為一個年輕的項目,真正告訴迭代和開發中,這既是一個優點,也是一個缺點。優點是它的未來具有無限的可能性,缺點是無法得到大項目長時間使用的檢驗。然而,目前CoreOS、Kubernetes和CloudFoundry等知名項目均在生產環境中使用了etcd,所以總的來說,etcd值得你去嘗試。

后續:etcd實現原理解讀

1、 架構

etcd架構圖

從etcd的架構圖中我們可以看到,etcd主要分為四個部分。

  • HTTP Server: 用于處理用戶發送的API請求以及其它etcd節點的同步與心跳信息請求。
  • Store:用于處理etcd支持的各類功能的事務,包括數據索引、節點狀態變更、監控與反饋、事件處理與執行等等,是etcd對用戶提供的大多數API功能的具體實現。
  • Raft:Raft強一致性算法的具體實現,是etcd的核心。
  • WAL:Write Ahead Log(預寫式日志),是etcd的數據存儲方式。除了在內存中存有所有數據的狀態以及節點的索引以外,etcd就通過WAL進行持久化存儲。WAL中,所有的數據提交前都會事先記錄日志。Snapshot是為了防止數據過多而進行的狀態快照;Entry表示存儲的具體日志內容。

通常,一個用戶的請求發送過來,會經由HTTP Server轉發給Store進行具體的事務處理,如果涉及到節點的修改,則交給Raft模塊進行狀態的變更、日志的記錄,然后再同步給別的etcd節點以確認數據提交,最后進行數據的提交,再次同步。

2 新版etcd重要變更列表

  • 獲得了IANA認證的端口,2379用于客戶端通信,2380用于節點通信,與原先的(4001 peers / 7001 clients)共用。
  • 每個節點可監聽多個廣播地址。監聽的地址由原來的一個擴展到多個,用戶可以根據需求實現更加復雜的集群環境,如一個是公網IP,一個是虛擬機(容器)之類的私有IP。
  • etcd可以代理訪問leader節點的請求,所以如果你可以訪問任何一個etcd節點,那么你就可以無視網絡的拓撲結構對整個集群進行讀寫操作。
  • etcd集群和集群中的節點都有了自己獨特的ID。這樣就防止出現配置混淆,不是本集群的其他etcd節點發來的請求將被屏蔽。
  • etcd集群啟動時的配置信息目前變為完全固定,這樣有助于用戶正確配置和啟動。
  • 運行時節點變化(Runtime Reconfiguration)。用戶不需要重啟 etcd 服務即可實現對 etcd 集群結構進行變更。啟動后可以動態變更集群配置。
  • 重新設計和實現了Raft算法,使得運行速度更快,更容易理解,包含更多測試代碼。
  • Raft日志現在是嚴格的只能向后追加、預寫式日志系統,并且在每條記錄中都加入了CRC校驗碼。
  • 啟動時使用的_etcd/* 關鍵字不再暴露給用戶
  • 廢棄集群自動調整功能的standby模式,這個功能使得用戶維護集群更困難。
  • 新增Proxy模式,不加入到etcd一致性集群中,純粹進行代理轉發。
  • ETCD_NAME(-name)參數目前是可選的,不再用于唯一標識一個節點。
  • 摒棄通過配置文件配置 etcd 屬性的方式,你可以用環境變量的方式代替。
  • 通過自發現方式啟動集群必須要提供集群大小,這樣有助于用戶確定集群實際啟動的節點數量。

3 etcd概念詞匯表

  • Raft:etcd所采用的保證分布式系統強一致性的算法。
  • Node:一個Raft狀態機實例。
  • Member: 一個etcd實例。它管理著一個Node,并且可以為客戶端請求提供服務。
  • Cluster:由多個Member構成可以協同工作的etcd集群。
  • Peer:對同一個etcd集群中另外一個Member的稱呼。
  • Client: 向etcd集群發送HTTP請求的客戶端。
  • WAL:預寫式日志,etcd用于持久化存儲的日志格式。
  • snapshot:etcd防止WAL文件過多而設置的快照,存儲etcd數據狀態。
  • Proxy:etcd的一種模式,為etcd集群提供反向代理服務。
  • Leader:Raft算法中通過競選而產生的處理所有數據提交的節點。
  • Follower:競選失敗的節點作為Raft中的從屬節點,為算法提供強一致性保證。
  • Candidate:當Follower超過一定時間接收不到Leader的心跳時轉變為Candidate開始競選。
  • Term:某個節點成為Leader到下一次競選時間,稱為一個Term。
  • Index:數據項編號。Raft中通過Term和Index來定位數據。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容