服務發現之 Etcd VS Consul

抄自這裏html

 

************************************************************************************************redis

網上找來找去都是zk和etcd的比較,和consul的比較不多,這個感受還算靠譜,也在別的地方看到過對consul的吐槽,記錄下算法

************************************************************************************************服務器

 

導語網絡

在分佈式微服務架構中,一個應用可能由一組職責單一化的服務組成。這時候就須要一個註冊服務的機制,註冊某個服務或者某個節點是可用的,還須要一個發現服務的機制來找到哪些服務或者哪些節點還在提供服務。多線程

在實際應用中,一般還都須要一個配置文件告訴咱們一些配置信息,好比數據鏈接的地址,redis 的地址等等。但不少時候,咱們想要動態地在不修改代碼的狀況下獲得這些信息,而且能很好地管理它們。架構

有了這些需求,因而發展出了一系列的開源框架,好比 ZooKeeper, Etcd, Consul 等等。框架

這些框架通常會提供這樣的服務:分佈式

服務註冊
主機名,端口號,版本號,或者一些環境信息。微服務

服務發現
可讓客戶端拿到服務端地址。

一個分佈式的通用 k/v 存儲系統
基於 Paxos 算法或者 Raft 算法

領導者選舉 (Leader Election)

其它一些例子:
分佈式鎖 (Distributed locking)
原子廣播 (Atomic broadcast)
序列號 (Sequence numbers)

咱們都知道 CAP 是 Eric Brewer 提出的分佈式系統三要素:
強一致性 (Consistency)
可用性 (Availability)
分區容忍性 (Partition Tolerance)

幾乎全部的服務發現和註冊方案都是 CP 系統,也就是說知足了在同一個數據有多個副本的狀況下,對於數據的更新操做達到最終的效果和操做一份數據是同樣的,可是在出現網絡分區(分區間的節點沒法進行網絡通訊)這樣的故障的時候,在節點之間恢復通訊而且同步數據以前,一些節點將會沒法提供服務(一些系統在節點丟失的狀況下支持 stale reads )。

ZooKeeper 做爲這類框架中歷史最悠久的之一,是由 Java 編寫。Java 在許多方面很是偉大,然而對於這種類型的工做仍是顯得有些沉重,也正由於其複雜性和對新鮮事物的嚮往,咱們第一時間就放棄了選擇它。

本文將從協議和應用層來比較 Etcd 和 Consul,並最終給出了筆者的偏好。

Etcd

Etcd 是一個使用 go 語言寫的分佈式 k/v 存儲系統。考慮到它是 coreos 公司的項目,以及在 GitHub 上的 star 數量 (9000+),Google 著名的容器管理工具 Kuberbetes 就是基於 Etcd 的。咱們最早考慮的就是它。

在介紹 Etcd 以前,咱們須要瞭解一些基本的概念。咱們知道在單臺服務器單個進程中維護一個狀態是很容易的,讀寫的時候不會產生衝突。即使在多進程或者多線程環境中,使用鎖機制或者協程(coroutine)也可讓讀寫有序地進行。可是在分佈式系統中,狀況就會複雜不少,服務器可能崩潰,節點間的機器可能網絡不通等等。因此一致性協議就是用來在一個集羣裏的多臺機器中維護一個一致的狀態。

不少的分佈式系統都會採用 Paxos 協議,可是 Paxos 協議難以理解,而且在實際實現中差異比較大。因此 Etcd 選擇了 Raft 做爲它的一致性協議。Raft 是 Diego Ongaro 和 John Ousterhout 在 ‘In Search of an Understandable Consensus Algorithm’ 中提出的。它在犧牲不多可用性,達到類似功能的狀況下,對 Paxos 作了很大的優化,而且比 Paxos 簡單易懂不少。

它主要集中在解決兩個問題:

領導者選舉(Leader Election)
Raft 先經過領導選舉選出一個 Leader,後續的一致性維護都由 Leader 來完成,這就簡化了一致性的問題。Raft 會保證一個時間下只會有一個 Leader,而且在超過一半節點投票的狀況下才會被選爲 Leader。當 Leader 掛掉的時候,新的 Leader 將會被選出來。

日誌複製 (Log Replication)
爲了維護狀態,系統會記錄下來全部的操做命令日誌。Leader 在收到客戶端操做命令後,會追加到日誌的尾部。而後 Leader 會向集羣裏全部其它節點發送 AppendEntries RPC 請求,每一個節點都經過兩階段提交來複制命令,這保證了大部分的節點都能完成。

在實際的應用中,通常 Etcd 集羣以 5 個或者 7 個爲宜,能夠忍受 2 個或者 3 個節點掛掉,爲何不是越多越好呢?是出於性能的考慮,由於節點多了之後,日誌的複製會致使 CPU 和網絡都出現瓶頸。

Etcd 的 API 比較簡單,能夠對一個目錄或者一個 key 進行 GET,PUT,DELETE 操做,是基於 HTTP 的。Etcd 提供 watch 某個目錄或者某個 key 的功能,客戶端和 Etcd 集羣之間保持着長鏈接 (long polling)。基於這個長鏈接,一旦數據發生改變,客戶端立刻就會收到通知,而且返回的結果是改變後的值和改變前的值,這一點在實際應用中會頗有用(這也是後面的 Consul 的槽點之一)。

Etcd 的 watch 和在通常狀況下不會漏掉任何的變動。由於 Etcd 不只存儲了當前的鍵值對,還存儲了最近的變動記錄,因此若是一個落後於當前狀態的 watch 仍是能夠經過遍歷歷史變動記錄來獲取到全部的更新。Etcd 還支持 CompareAndSwap 這個原子操做,首先對一個 key 進行值比較,只有結果一致纔會進行下一步的賦值操做。利用這個特性就像利用 x86 的 CAS 實現鎖同樣能夠實現分佈式鎖。

在 Etcd 中有個 proxy 的概念,它實際上是個轉發服務器,啓動的時候須要指定集羣的地址,而後就能夠轉發客戶端的請求到集羣,它自己不存儲數據。通常來講,在每一個服務節點都會啓動一個 proxy,因此這個 proxy 也是一個本地 proxy,這樣服務節點就不須要知道 Etcd 集羣的具體地址,只須要請求本地 proxy。以前提到過一個 k/v 系統還應該支持 leader election,Etcd 能夠經過 TTL (time to live) key 來實現。

Consul

Consul 和 Etcd 同樣也有兩種節點,一種叫 client (和 Etcd 的 proxy 同樣) 只負責轉發請求,另外一種是 server,是真正存儲和處理事務的節點。

Consul 使用基於 Serf 實現的 gossip 協議來管理從屬關係,失敗檢測,事件廣播等等。gossip 協議是一個神奇的一致性協議,之因此取名叫 gossip 是由於這個協議是模擬人類中傳播謠言的行爲而來。要傳播謠言就要有種子節點,種子節點每秒都會隨機向其它節點發送本身所擁有的節點列表,以及須要傳播的消息。任何新加入的節點,就在這種傳播方式下很快地被全網所知道。這個協議的神奇就在於它從設計開始就沒想要信息必定要傳遞給全部的節點,可是隨着時間的增加,在最終的某一時刻,全網會獲得相同的信息。固然這個時刻可能僅僅存在於理論,永遠不可達。

Consul 使用了兩個不一樣的 gossip pool,分別叫作 LAN 和 WAN,這是由於 Consul 原生支持多數據中心。在一個數據中心內部,LAN gossip pool 包含了這個數據中心全部的節點,包括 proxy 和 servers。WAN pool 是全局惟一的,全部數據中心的 servers 都在這個 pool 中。這兩個 pool 的區別就是 LAN 處理的是數據中心內部的失敗檢測,事件廣播等等,而 WAN 關心的是跨數據中心的。除了 gossip 協議以外,Consul 還使用了 Raft 協議來進行 leader election,選出 leader 以後複製日誌的過程和 Etcd 基本一致。

回到應用層面上來講,Consul 更像是一個 full stack 的解決方案,它不只提供了一致性 k/v 存儲,還封裝了服務發現,健康檢查,內置了 DNS server 等等。這看上去很是美好,簡直能夠開箱即用。因而,咱們初步選定了 Consul 做爲咱們的服務發現和動態配置的框架。但現實每每是冰冷的,在深刻研究它的 API 以後發現了比較多的坑,可能設計者有他本身的考慮。

在使用獲取全部 services 的 API 的時候返回的只是全部服務的名字和 tag,若是想要每一個服務的具體信息,你還須要挨個去請求。這在客戶端就會十分不方便,由於在筆者看來,獲取全部服務的列表以及具體信息應該是一個很常見的需求,而且請求的次數越少越好。

若是 watch 服務是否有變化,當值發生改變的時候,返回的結果竟然是至關於從新讀取全部 services,沒有可以體現出服務信息的變化,這會致使客戶端很難進行更新操做。

健康檢查是 Consul 的內置功能,在註冊一個服務的時候能夠加上自定義的健康檢查,這聽上去很不錯。可是若是你忘記給你某個服務加上健康檢查,那它在各類 API 的返回結果中變得難以預料。

結語

在折騰了數天以後,最終咱們決定迴歸 Etcd,事實證實這個決定是正確的。咱們基於 Etcd 實現了穩定的服務發現和動態配置功能,固然還有一些比較細節的問題沒有在文中闡述,歡迎一塊兒探討。

相關文章
相關標籤/搜索