一、概述
etcd是一個高可用的鍵值存儲系統,主要用於共享配置和服務發現。etcd是由CoreOS開發並維護的,靈感來自於 ZooKeeper 和 Doozer,它使用Go語言編寫,並通過Raft一致性算法處理日志復制以保證強一致性。Raft是一個新的一致性算法,適用於分布式系統的日志復制,Raft通過選舉的方式來實現一致性。Google的容器集群管理系統Kubernetes、開源PaaS平台Cloud Foundry和CoreOS的Fleet都廣泛使用了etcd。在分布式系統中,如何管理節點間的狀態一直是一個難題,etcd像是專門為集群環境的服務發現和注冊而設計,它提供了數據TTL失效、數據改變監視、多值、目錄監聽、分布式鎖原子操作等功能,可以方便的跟蹤並管理集群節點的狀態。
etcd的特性如下:
- 簡單: 支持curl方式的用戶API(HTTP+JSON)
- 安全: 可選的SSL客戶端證書認證
- 快速: 單實例每秒 1000 次寫操作
- 可靠: 使用Raft保證一致性
二、安裝和使用
安裝etcd
etcd的安裝非常簡單,可以直接下載編譯后的可執行文件,下載地址:https://github.com/coreos/etcd/releases
curl -L https://github.com/coreos/etcd/releases/download/v3.0.6/etcd-v3.0.6-linux-amd64.tar.gz -o etcd-v3.0.6-linux-amd64.tar.gz tar xzvf etcd-v3.0.6-linux-amd64.tar.gz && cd etcd-v3.0.6-linux-amd64 ./etcd --version
etcd命令行接口使用
etcd支持http RESTful API,支持get查詢,post,delete,put等操作。為了便於理解,可將它存儲數據的框架看做一個文件系統,可以創建目錄和“文件”,每個“文件”名就是一個key,每個“文件”的內容就是它的value,目錄沒有value只能包含子目錄或者“文件”,可以通過RESTful API來獲取這些key的值或者設置這些key的值。
*設置一個key的value
curl -s http://127.0.0.1:2379/v2/keys/message -X PUT -d value="Hello world" |jq .

*獲取一個key的value
curl -s http://127.0.0.1:2379/v2/keys/message |jq .

*改變一個key的value
curl -s http://127.0.0.1:2379/v2/keys/message -X PUT -d value="Hello etcd" |jq .

*刪除一個key節點
curl -s http://127.0.0.1:2379/v2/keys/message -X DELETE |jq .

*使用ttl(即設置一個key的值並給這個key加一個生命周期,當超過這個時間該值沒有被訪問則自動被刪除)
curl -s http://127.0.0.1:2379/v2/keys/foo -X PUT -d value=bar -d ttl=5 |jq .

*watch一個值的變化
curl -s http://127.0.0.1:2379/v2/keys/foo?wait=true
該命令調用之后會阻塞進程,直到這個值發生變化才能返回,當改變一個key的值,或者刪除等操作發生時,該等待就會返回結果。
*創建一個目錄
curl -s http://127.0.0.1:2379/v2/keys/dir -XPUT -d dir=true |jq .

*列舉一個目錄
curl -s http://127.0.0.1:2379/v2/keys/dir
*遞歸列舉一個目錄
curl -s http://127.0.0.1:2379/v2/keys/dir?recursive=true
監控一個目錄下的所有key的變化,包括子目錄的。可以使用命令:
curl -s http://127.0.0.1:2379/v2/keys/dir?recursive=true&wait=true
*刪除一個目錄
curl -s http://127.0.0.1:2379/v2/keys/dir?dir=true -XDELETE
三、應用場景
場景一:服務發現(Service Discovery)
服務發現要解決的也是分布式系統中最常見的問題之一,即在同一個分布式集群中的進程或服務,要如何才能找到對方並建立連接。本質上來說,服務發現就是想要了解集群中是否有進程在監聽udp或tcp端口,並且通過名字就可以查找和連接。

圖1 服務發現示意圖
微服務協同工作架構中,服務動態添加。隨着Docker容器的流行,多種微服務共同協作,構成一個相對功能強大的架構的案例越來越多。透明化的動態添加這些服務的需求也日益強烈。通過服務發現機制,在etcd中注冊某個服務名字的目錄,在該目錄下存儲可用的服務節點的IP。在使用服務的過程中,只要從服務目錄下查找可用的服務節點去使用即可。

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

圖3 消息發布與訂閱
場景三:分布式通知與協調
這里說到的分布式通知與協調,與消息發布和訂閱有些相似。都用到了etcd中的Watcher機制,通過注冊與異步通知機制,實現分布式環境下不同系統之間的通知與協調,從而對數據變更做到實時處理。實現方式通常是這樣:不同系統都在etcd上對同一個目錄進行注冊,同時設置Watcher觀測該目錄的變化(如果對子目錄的變化也有需要,可以設置遞歸模式),當某個系統更新了etcd的目錄,那么設置了Watcher的系統就會收到通知,並作出相應處理。
場景四:分布式鎖
因為etcd使用Raft算法保持了數據的強一致性,某次操作存儲到集群中的值必然是全局一致的,所以很容易實現分布式鎖。鎖服務有兩種使用方式,一是保持獨占,二是控制時序。
- 保持獨占即所有獲取鎖的用戶最終只有一個可以得到。etcd為此提供了一套實現分布式鎖原子操作CAS(CompareAndSwap)的API。通過設置prevExist值,可以保證在多個節點同時去創建某個目錄時,只有一個成功。而創建成功的用戶就可以認為是獲得了鎖。
- 控制時序,即所有想要獲得鎖的用戶都會被安排執行,但是獲得鎖的順序也是全局唯一的,同時決定了執行順序。etcd為此也提供了一套API(自動創建有序鍵),對一個目錄建值時指定為POST動作,這樣etcd會自動在目錄下生成一個當前最大的值為鍵,存儲這個新的值(客戶端編號)。同時還可以使用API按順序列出所有當前目錄下的鍵值。此時這些鍵的值就是客戶端的時序,而這些鍵中存儲的值可以是代表客戶端的編號。

圖4 分布式鎖
