ETCD持久化監聽數據丟失小記

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變化)相關類型事件:setgetcreateupdatedeleteexpirecompareAndSwapcompareAndDelete。在返回的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:

  1. X-Etcd-Index代表etcd當前index,爲所有key共享。單挑遞增總是大於或等於modifiedIndex,而這個modifiedIndex是etcd已經存儲事件的index
  2. 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丟失,重新再同步需要保證數據一致、同步前後的變化通知上層監聽。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章