etcd是CoreOS開發的分佈式高可用鍵值存儲系統。隨着CoreOS和K8s等項目在開源社區日益火熱,etcd組件也漸漸爲開發人員所關注。
etcd也是受到ZooKeeper與doozer啓發而催生的項目,除了擁有類似功能,更專注於以下四點。
- 簡單:基於HTTP+JSON的API讓你用curl就可以輕鬆使用(V3版本不再使用JSON)。
- 安全:可選SSL客戶認證機制。
- 快速:每個實例每秒支持一千次寫操作。
- 可信:使用Raft算法充分實現了分佈式。
在項目對比etcd和zookeeper之後,etcd更輕型容易部署安裝使用,zk特性比較豐富,但已老態龍鍾,需要點新鮮選擇。在去年我黨生日迎來了etcd v3(使用gRPC、改變key ttl使用租約等),蛋疼的發現java客戶端etcd4j不支持v3版本,v2版本目前可以滿足我們需求,繼續使用etcd,後續會關注etcd4j更新。本文基於etcd v2版本使用。
etcd事件監聽
etcd沒有提供被動監聽的實現,我們可以主動輪訓監聽key的變化。如果想監聽其子節點可以通過recursive=true
參數
curl http://127.0.0.1:2379/v2/keys/foo?wait=true
對/foo的改變會受到通知和返回相關變化事件
HTTP/1.1 200 OK
Content-Type: application/json
X-Etcd-Cluster-Id: e88d54f6225f06ad
X-Etcd-Index: 271
X-Raft-Index: 872202
X-Raft-Term: 5
Date: Sat, 26 Sep 2015 08:43:17 GMT
Transfer-Encoding: chunked
{
"action":
"set",
"node": {
"createdIndex": 7,
"key": "/foo",
"modifiedIndex": 7,
"value": "bar"
},
"prevNode": {
"createdIndex": 6,
"key": "/foo",
"modifiedIndex": 6,
"value": "bar"
}
}
etcd中的數據變化(包括目錄和key、value變化)相關類型事件:set
、get
、create
、update
、delete
、expire
、compareAndSwap
、compareAndDelete
。在返回的http response
中的action
屬性就是事件類型,如上圖所示。
etcd記錄下最近1000次事件變化,使用index我們可以watch其key在過去發生的變化。使用node的modifiedIndex+1就可以監聽下一次事件:curl 'http://127.0.0.1:2379/v2/keys/foo?wait=true&waitIndex=8'
但當事件突發比如1秒內產生幾千條事件,事件監聽處理比較慢或者未監聽是發生了客戶端事件丟失。當我們index超過etcd記錄的返回,就返回如下消息:
{
"errorCode" : 401 ,
"message" : "The event in requested index is outdated and cleared" ,
"cause" : "the requested history has been cleared [1008/8]" ,
"index" : 2007
}
官方文檔中推薦使用X-Etcd-Index+1作爲waitIndex代替使用node的modifiedIndex+1:
- X-Etcd-Index代表etcd當前index,爲所有key共享。單挑遞增總是大於或等於modifiedIndex,而這個modifiedIndex是etcd已經存儲事件的index
- modifiedIndex和X-Etcd-Index之間不代表有事件發生,當fetch 相關key不會有事件返回。
使用modifiedIndex+1
只是功能表示後續監聽,它比X-Etcd-Index+1
小,很可能相關事件已經被清除,可能會受到401EventIndexCleared
錯誤。在初始監聽或斷開重新監聽,index應該使用X-Etcd-Index+1
,而不是modifiedIndex+1
。
上述只能監聽一次事件變化,Etcd還提供流式監聽,在curl的時候加stream=true
參數,會和etcd服務端建議http長連接,後續的每個事件都會通過這個http chunk推送給客戶端。相對比一次性監聽,更簡潔,可靠性更高。但有一問題,流式監聽監聽從命令發出之後的時間,先前的時間是監聽不到的,如果再加waitIndex參數,waitIndex小於或等於啓動監聽時etcd的X-Etcd-Index,只能接受到滿足條件的事件,後續不再接收,只能收到一個事件。waitIndex大於X-Etcd-Index無效。
Etcd4j並沒有支持流式監聽,而且流式監聽無法做到監聽時的客戶端和服務端數據同步。我們使用Etcd4j實現監聽持久化,實現如下特性:
- 事件類型簡單化,etcd的set、get、create、update、delete、expire、compareAndSwap、compareAndDelete事件類型,簡化成Add、Upate、Removed三種類型
- 支持目錄、key全量變化監聽,支持子節點變化監聽。例如etcd刪除目錄時子節點也隨之刪除,只產生刪除目錄事件,而子節點刪除也需要通知其刪除事件。
- 需要解決事件突發(超過etcd記錄event數量)造成監聽index丟失,重新再同步需要保證數據一致、同步前後的變化通知上層監聽。