提到etcd很多人第一反應就是一個鍵值存儲倉庫。不過etcd官方文檔的定義卻是這樣的:
A highly-available key value store for shared configuration and service discovery.
包含了配置共享和服務發(fā)現(xiàn)步势。
etcd作為一個受到ZooKeeper與doozer啟發(fā)而催生的項目氧猬,除了擁有與之類似的功能外,更專注于以下四點坏瘩。
- 簡單:基于HTTP+JSON的API讓你用curl就可以輕松使用盅抚。
- 安全:可選SSL客戶認證機制。
- 快速:每個實例每秒支持一千次寫操作倔矾。
- 可信:使用Raft算法充分實現(xiàn)了分布式妄均。
接下來將針對剖析一些etcd的經(jīng)典使用場景,來看看etcd這個基于Raft強一致性算法的分布式存儲倉庫能給我們帶來哪些幫助破讨。
值得注意的是丛晦,分布式系統(tǒng)中的數(shù)據(jù)分為控制數(shù)據(jù)和應用數(shù)據(jù)奕纫。使用etcd的場景默認處理的數(shù)據(jù)都是控制數(shù)據(jù)提陶,對于應用數(shù)據(jù),只推薦數(shù)據(jù)量很小匹层,但是更新訪問頻繁的情況隙笆。
場景一:服務發(fā)現(xiàn)(Service Discovery)
在分布式系統(tǒng)中“服務發(fā)現(xiàn)”也是比較常見的問題:在同一個集群環(huán)境中不同的應用或服務,如何能夠找到對方并建立連接升筏,來完成后續(xù)的行為撑柔。本質(zhì)上來說,服務發(fā)現(xiàn)就是想要知道集群中是否有進程在監(jiān)聽udp或tcp端口您访,并能通過名字就可以查找和連接铅忿。而要解決服務發(fā)現(xiàn)的問題,需要滿足如下三個方面灵汪,缺一不可檀训。
- 一個強一致性、高可用的服務存儲目錄: 基于Raft算法的etcd天生就是這樣一個強一致性高可用的服務存儲目錄【安全的記錄集群中的應用或服務的信息(地址享言、端口等)】峻凫。
- 一種注冊服務和監(jiān)控服務健康狀態(tài)的機制:用戶可以在etcd中注冊服務,并且對注冊的服務設(shè)置key TTL览露,定時保持服務的心跳以達到監(jiān)控健康狀態(tài)的效果荧琼。【能夠完成新的應用或服務的注冊添加進來,同樣也能對現(xiàn)有的服務是否可用進行監(jiān)控】
- 一種查找和連接服務的機制: 通過在etcd指定的主題下注冊的服務也能在對應的主題下查找到命锄。為了確保連接堰乔,我們可以在每個服務機器上都部署一個Proxy模式的etcd,這樣就可以確保能訪問etcd集群的服務都能互相連接脐恩『瓶迹【已有的服務當被使用能夠被找到并能連接】
來看服務發(fā)現(xiàn)對應的具體場景:
- 微服務協(xié)同工作架構(gòu)中,服務動態(tài)添加被盈。隨著Docker容器的流行析孽,多種微服務共同協(xié)作,構(gòu)成一個相對功能強大的架構(gòu)的案例越來越多只怎。透明化的動態(tài)添加這些服務的需求也日益強烈袜瞬。通過服務發(fā)現(xiàn)機制,在etcd中注冊某個服務名字的目錄身堡,在該目錄下存儲可用的服務節(jié)點的IP邓尤。在使用服務的過程中,只要從服務目錄下查找可用的服務節(jié)點去使用即可贴谎。
- PaaS平臺中應用多實例與實例故障重啟透明化汞扎。PaaS平臺中的應用一般都有多個實例,通過域名擅这,不僅可以透明的對這多個實例進行訪問澈魄,而且還可以做到負載均衡。但是應用的某個實例隨時都有可能故障重啟仲翎,這時就需要動態(tài)的配置域名解析(路由)中的信息痹扇。通過etcd的服務發(fā)現(xiàn)功能就可以輕松解決這個動態(tài)配置的問題。
場景二:消息發(fā)布與訂閱
在分布式系統(tǒng)中溯香,最適用的一種組件間通信方式就是消息發(fā)布與訂閱鲫构。即構(gòu)建一個配置共享中心,數(shù)據(jù)提供者在這個配置中心發(fā)布消息玫坛,而消息使用者則訂閱他們關(guān)心的主題结笨,一旦主題有消息發(fā)布,就會實時通知訂閱者湿镀。通過這種方式可以做到分布式系統(tǒng)配置的集中式管理與動態(tài)更新炕吸。
- 應用中用到的一些配置信息放到etcd上進行集中管理。這類場景的使用方式通常是這樣:應用在啟動的時候主動從etcd獲取一次配置信息肠骆,同時算途,在etcd節(jié)點上注冊一個Watcher并等待,以后每次配置有更新的時候蚀腿,etcd都會實時通知訂閱者嘴瓤,以此達到獲取最新配置信息的目的扫外。
- 分布式搜索服務中,索引的元信息和服務器集群機器的節(jié)點狀態(tài)存放在etcd中廓脆,供各個客戶端訂閱使用筛谚。使用etcd的key TTL功能可以確保機器狀態(tài)是實時更新的。
- 分布式日志收集系統(tǒng)停忿。這個系統(tǒng)的核心工作是收集分布在不同機器的日志驾讲。收集器通常是按照應用(或主題)來分配收集任務單元,因此可以在etcd上創(chuàng)建一個以應用(主題)命名的目錄P席赂,并將這個應用(主題相關(guān))的所有機器ip吮铭,以子目錄的形式存儲到目錄P上,然后設(shè)置一個etcd遞歸的Watcher颅停,遞歸式的監(jiān)控應用(主題)目錄下所有信息的變動谓晌。這樣就實現(xiàn)了機器IP(消息)變動的時候,能夠?qū)崟r通知到收集器調(diào)整任務分配癞揉。
- 系統(tǒng)中信息需要動態(tài)自動獲取與人工干預修改信息請求內(nèi)容的情況纸肉。通常是暴露出接口,例如JMX接口喊熟,來獲取一些運行時的信息柏肪。引入etcd之后,就不用自己實現(xiàn)一套方案了芥牌,只要將這些信息存放到指定的etcd目錄中即可烦味,etcd的這些目錄就可以通過HTTP的接口在外部訪問。
場景三:負載均衡
在場景一中也提到了負載均衡胳泉,本文所指的負載均衡均為軟負載均衡拐叉。分布式系統(tǒng)中岩遗,為了保證服務的高可用以及數(shù)據(jù)的一致性扇商,通常都會把數(shù)據(jù)和服務部署多份,以此達到對等服務宿礁,即使其中的某一個服務失效了案铺,也不影響使用。由此帶來的壞處是數(shù)據(jù)寫入性能下降梆靖,而好處則是數(shù)據(jù)訪問時的負載均衡控汉。因為每個對等服務節(jié)點上都存有完整的數(shù)據(jù),所以用戶的訪問流量就可以分流到不同的機器上返吻。
- etcd本身分布式架構(gòu)存儲的信息訪問支持負載均衡姑子。etcd集群化以后,每個etcd的核心節(jié)點都可以處理用戶的請求测僵。所以街佑,把數(shù)據(jù)量小但是訪問頻繁的消息數(shù)據(jù)直接存儲到etcd中也是個不錯的選擇谢翎,如業(yè)務系統(tǒng)中常用的二級代碼表(在表中存儲代碼,在etcd中存儲代碼所代表的具體含義沐旨,業(yè)務系統(tǒng)調(diào)用查表的過程森逮,就需要查找表中代碼的含義)。
- 利用etcd維護一個負載均衡節(jié)點表磁携。etcd可以監(jiān)控一個集群中多個節(jié)點的狀態(tài)褒侧,當有一個請求發(fā)過來后,可以輪詢式的把請求轉(zhuǎn)發(fā)給存活著的多個狀態(tài)谊迄。類似KafkaMQ闷供,通過ZooKeeper來維護生產(chǎn)者和消費者的負載均衡。同樣也可以用etcd來做ZooKeeper的工作统诺。
場景四:分布式通知與協(xié)調(diào)
這里說到的分布式通知與協(xié)調(diào)这吻,與消息發(fā)布和訂閱有些相似。都用到了etcd中的Watcher機制篙议,通過注冊與異步通知機制唾糯,實現(xiàn)分布式環(huán)境下不同系統(tǒng)之間的通知與協(xié)調(diào),從而對數(shù)據(jù)變更做到實時處理鬼贱。實現(xiàn)方式通常是這樣:不同系統(tǒng)都在etcd上對同一個目錄進行注冊移怯,同時設(shè)置Watcher觀測該目錄的變化(如果對子目錄的變化也有需要,可以設(shè)置遞歸模式)这难,當某個系統(tǒng)更新了etcd的目錄舟误,那么設(shè)置了Watcher的系統(tǒng)就會收到通知,并作出相應處理姻乓。
- 通過etcd進行低耦合的心跳檢測嵌溢。檢測系統(tǒng)和被檢測系統(tǒng)通過etcd上某個目錄關(guān)聯(lián)而非直接關(guān)聯(lián)起來,這樣可以大大減少系統(tǒng)的耦合性蹋岩。
- 通過etcd完成系統(tǒng)調(diào)度赖草。某系統(tǒng)有控制臺和推送系統(tǒng)兩部分組成,控制臺的職責是控制推送系統(tǒng)進行相應的推送工作剪个。管理人員在控制臺作的一些操作秧骑,實際上是修改了etcd上某些目錄節(jié)點的狀態(tài),而etcd就把這些變化通知給注冊了Watcher的推送系統(tǒng)客戶端扣囊,推送系統(tǒng)再作出相應的推送任務乎折。
- 通過etcd完成工作匯報。大部分類似的任務分發(fā)系統(tǒng)侵歇,子任務啟動后骂澄,到etcd來注冊一個臨時工作目錄,并且定時將自己的進度進行匯報(將進度寫入到這個臨時目錄)惕虑,這樣任務管理者就能夠?qū)崟r知道任務進度坟冲。
場景五:分布式鎖
因為etcd使用Raft算法保持了數(shù)據(jù)的強一致性士修,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現(xiàn)分布式鎖樱衷。鎖服務有兩種使用方式棋嘲,一是保持獨占,二是控制時序矩桂。
- 保持獨占即所有獲取鎖的用戶最終只有一個可以得到沸移。etcd為此提供了一套實現(xiàn)分布式鎖原子操作CAS(CompareAndSwap)的API。通過設(shè)置prevExist值侄榴,可以保證在多個節(jié)點同時去創(chuàng)建某個目錄時雹锣,只有一個成功。而創(chuàng)建成功的用戶就可以認為是獲得了鎖癞蚕。
- 控制時序蕊爵,即所有想要獲得鎖的用戶都會被安排執(zhí)行,但是獲得鎖的順序也是全局唯一的桦山,同時決定了執(zhí)行順序攒射。etcd為此也提供了一套API(自動創(chuàng)建有序鍵),對一個目錄建值時指定為POST動作恒水,這樣etcd會自動在目錄下生成一個當前最大的值為鍵会放,存儲這個新的值(客戶端編號)。同時還可以使用API按順序列出所有當前目錄下的鍵值钉凌。此時這些鍵的值就是客戶端的時序咧最,而這些鍵中存儲的值可以是代表客戶端的編號。
場景六:分布式隊列
分布式隊列的常規(guī)用法與場景五中所描述的分布式鎖的控制時序用法類似御雕,即創(chuàng)建一個先進先出的隊列矢沿,保證順序。
另一種比較有意思的實現(xiàn)是在保證隊列達到某個條件時再統(tǒng)一按順序執(zhí)行酸纲。這種方法的實現(xiàn)可以在/queue這個目錄中另外建立一個/queue/condition節(jié)點捣鲸。
- condition可以表示隊列大小。比如一個大的任務需要很多小任務就緒的情況下才能執(zhí)行福青,每次有一個小任務就緒摄狱,就給這個condition數(shù)字加1,直到達到大任務規(guī)定的數(shù)字无午,再開始執(zhí)行隊列里的一系列小任務,最終執(zhí)行大任務祝谚。
- condition可以表示某個任務在不在隊列宪迟。這個任務可以是所有排序任務的首個執(zhí)行程序,也可以是拓撲結(jié)構(gòu)中沒有依賴的點交惯。通常次泽,必須執(zhí)行這些任務后才能執(zhí)行隊列中的其他任務穿仪。
- condition還可以表示其它的一類開始執(zhí)行任務的通知∫饣纾可以由控制程序指定啊片,當condition出現(xiàn)變化時,開始執(zhí)行隊列任務玖像。
場景七:集群監(jiān)控與Leader競選
通過etcd來進行監(jiān)控實現(xiàn)起來非常簡單并且實時性強紫谷。
- 前面幾個場景已經(jīng)提到Watcher機制,當某個節(jié)點消失或有變動時捐寥,Watcher會第一時間發(fā)現(xiàn)并告知用戶笤昨。
- 節(jié)點可以設(shè)置TTL key,比如每隔30s發(fā)送一次心跳使代表該機器存活的節(jié)點繼續(xù)存在握恳,否則節(jié)點消失瞒窒。
這樣就可以第一時間檢測到各節(jié)點的健康狀態(tài),以完成集群的監(jiān)控要求乡洼。
另外崇裁,使用分布式鎖,可以完成Leader競選束昵。這種場景通常是一些長時間CPU計算或者使用IO操作的機器寇壳,只需要競選出的Leader計算或處理一次,就可以把結(jié)果復制給其他的Follower妻怎。從而避免重復勞動壳炎,節(jié)省計算資源。
這個的經(jīng)典場景是搜索系統(tǒng)中建立全量索引逼侦。如果每個機器都進行一遍索引的建立匿辩,不但耗時而且建立索引的一致性不能保證。通過在etcd的CAS機制同時創(chuàng)建一個節(jié)點榛丢,創(chuàng)建成功的機器作為Leader铲球,進行索引計算,然后把計算結(jié)果分發(fā)到其它節(jié)點晰赞。
場景八:為什么用etcd而不用ZooKeeper稼病?
etcd實現(xiàn)的這些功能,ZooKeeper都能實現(xiàn)掖鱼。那么為什么要用etcd而非直接使用ZooKeeper呢然走?
相較之下,ZooKeeper有如下缺點:
- 復雜戏挡。ZooKeeper的部署維護復雜芍瑞,管理員需要掌握一系列的知識和技能;而Paxos強一致性算法也是素來以復雜難懂而聞名于世褐墅;另外拆檬,ZooKeeper的使用也比較復雜洪己,需要安裝客戶端,官方只提供了Java和C兩種語言的接口竟贯。
- Java編寫答捕。這里不是對Java有偏見,而是Java本身就偏向于重型應用屑那,它會引入大量的依賴拱镐。而運維人員則普遍希望保持強一致、高可用的機器集群盡可能簡單齐莲,維護起來也不易出錯痢站。
- 發(fā)展緩慢。Apache基金會項目特有的“Apache Way”在開源界飽受爭議选酗,其中一大原因就是由于基金會龐大的結(jié)構(gòu)以及松散的管理導致項目發(fā)展緩慢阵难。
而etcd作為一個后起之秀,其優(yōu)點也很明顯芒填。
- 簡單呜叫。使用Go語言編寫部署簡單;使用HTTP作為接口使用簡單殿衰;使用Raft算法保證強一致性讓用戶易于理解朱庆。
- 數(shù)據(jù)持久化。etcd默認數(shù)據(jù)一更新就進行持久化闷祥。
- 安全娱颊。etcd支持SSL客戶端安全認證。
最后凯砍,etcd作為一個年輕的項目箱硕,真正告訴迭代和開發(fā)中,這既是一個優(yōu)點悟衩,也是一個缺點剧罩。優(yōu)點是它的未來具有無限的可能性,缺點是無法得到大項目長時間使用的檢驗座泳。然而惠昔,目前CoreOS、Kubernetes和CloudFoundry等知名項目均在生產(chǎn)環(huán)境中使用了etcd挑势,所以總的來說镇防,etcd值得你去嘗試。
后續(xù):etcd實現(xiàn)原理解讀
1薛耻、 架構(gòu)
從etcd的架構(gòu)圖中我們可以看到营罢,etcd主要分為四個部分。
- HTTP Server: 用于處理用戶發(fā)送的API請求以及其它etcd節(jié)點的同步與心跳信息請求饼齿。
- Store:用于處理etcd支持的各類功能的事務饲漾,包括數(shù)據(jù)索引、節(jié)點狀態(tài)變更缕溉、監(jiān)控與反饋考传、事件處理與執(zhí)行等等,是etcd對用戶提供的大多數(shù)API功能的具體實現(xiàn)证鸥。
- Raft:Raft強一致性算法的具體實現(xiàn)僚楞,是etcd的核心。
- WAL:Write Ahead Log(預寫式日志)枉层,是etcd的數(shù)據(jù)存儲方式泉褐。除了在內(nèi)存中存有所有數(shù)據(jù)的狀態(tài)以及節(jié)點的索引以外,etcd就通過WAL進行持久化存儲鸟蜡。WAL中膜赃,所有的數(shù)據(jù)提交前都會事先記錄日志。Snapshot是為了防止數(shù)據(jù)過多而進行的狀態(tài)快照揉忘;Entry表示存儲的具體日志內(nèi)容跳座。
通常,一個用戶的請求發(fā)送過來泣矛,會經(jīng)由HTTP Server轉(zhuǎn)發(fā)給Store進行具體的事務處理疲眷,如果涉及到節(jié)點的修改,則交給Raft模塊進行狀態(tài)的變更您朽、日志的記錄洞就,然后再同步給別的etcd節(jié)點以確認數(shù)據(jù)提交,最后進行數(shù)據(jù)的提交摄职,再次同步系谐。
2 新版etcd重要變更列表
- 獲得了IANA認證的端口,2379用于客戶端通信魂奥,2380用于節(jié)點通信菠剩,與原先的(4001 peers / 7001 clients)共用。
- 每個節(jié)點可監(jiān)聽多個廣播地址耻煤。監(jiān)聽的地址由原來的一個擴展到多個具壮,用戶可以根據(jù)需求實現(xiàn)更加復雜的集群環(huán)境,如一個是公網(wǎng)IP哈蝇,一個是虛擬機(容器)之類的私有IP棺妓。
- etcd可以代理訪問leader節(jié)點的請求,所以如果你可以訪問任何一個etcd節(jié)點炮赦,那么你就可以無視網(wǎng)絡(luò)的拓撲結(jié)構(gòu)對整個集群進行讀寫操作怜跑。
- etcd集群和集群中的節(jié)點都有了自己獨特的ID。這樣就防止出現(xiàn)配置混淆,不是本集群的其他etcd節(jié)點發(fā)來的請求將被屏蔽性芬。
- etcd集群啟動時的配置信息目前變?yōu)橥耆潭ㄏ靠簦@樣有助于用戶正確配置和啟動。
- 運行時節(jié)點變化(Runtime Reconfiguration)植锉。用戶不需要重啟 etcd 服務即可實現(xiàn)對 etcd 集群結(jié)構(gòu)進行變更辫樱。啟動后可以動態(tài)變更集群配置。
- 重新設(shè)計和實現(xiàn)了Raft算法俊庇,使得運行速度更快狮暑,更容易理解,包含更多測試代碼辉饱。
- Raft日志現(xiàn)在是嚴格的只能向后追加搬男、預寫式日志系統(tǒng),并且在每條記錄中都加入了CRC校驗碼彭沼。
- 啟動時使用的_etcd/* 關(guān)鍵字不再暴露給用戶
- 廢棄集群自動調(diào)整功能的standby模式缔逛,這個功能使得用戶維護集群更困難。
- 新增Proxy模式溜腐,不加入到etcd一致性集群中译株,純粹進行代理轉(zhuǎn)發(fā)。
- ETCD_NAME(-name)參數(shù)目前是可選的挺益,不再用于唯一標識一個節(jié)點歉糜。
- 摒棄通過配置文件配置 etcd 屬性的方式,你可以用環(huán)境變量的方式代替望众。
- 通過自發(fā)現(xiàn)方式啟動集群必須要提供集群大小匪补,這樣有助于用戶確定集群實際啟動的節(jié)點數(shù)量。
3 etcd概念詞匯表
- Raft:etcd所采用的保證分布式系統(tǒng)強一致性的算法烂翰。
- Node:一個Raft狀態(tài)機實例夯缺。
- Member: 一個etcd實例。它管理著一個Node甘耿,并且可以為客戶端請求提供服務踊兜。
- Cluster:由多個Member構(gòu)成可以協(xié)同工作的etcd集群。
- Peer:對同一個etcd集群中另外一個Member的稱呼佳恬。
- Client: 向etcd集群發(fā)送HTTP請求的客戶端捏境。
- WAL:預寫式日志,etcd用于持久化存儲的日志格式毁葱。
- snapshot:etcd防止WAL文件過多而設(shè)置的快照垫言,存儲etcd數(shù)據(jù)狀態(tài)。
- Proxy:etcd的一種模式倾剿,為etcd集群提供反向代理服務筷频。
- Leader:Raft算法中通過競選而產(chǎn)生的處理所有數(shù)據(jù)提交的節(jié)點。
- Follower:競選失敗的節(jié)點作為Raft中的從屬節(jié)點,為算法提供強一致性保證凛捏。
- Candidate:當Follower超過一定時間接收不到Leader的心跳時轉(zhuǎn)變?yōu)镃andidate開始競選担忧。
- Term:某個節(jié)點成為Leader到下一次競選時間,稱為一個Term葵袭。
- Index:數(shù)據(jù)項編號涵妥。Raft中通過Term和Index來定位數(shù)據(jù)乖菱。