日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Zookeeper開(kāi)源客戶端框架Curator簡(jiǎn)介

 昵稱597197 2014-08-04
Curator是Netflix開(kāi)源的一套ZooKeeper客戶端框架. Netflix在使用ZooKeeper的過(guò)程中發(fā)現(xiàn)ZooKeeper自帶的客戶端太底層, 應(yīng)用方在使用的時(shí)候需要自己處理很多事情, 于是在它的基礎(chǔ)上包裝了一下, 提供了一套更好用的客戶端框架. Netflix在用ZooKeeper的過(guò)程中遇到的問(wèn)題, 我們也遇到了, 所以開(kāi)始研究一下, 首先從他在github上的源碼, wiki文檔以及Netflix的技術(shù)blog入手. 

看完官方的文檔之后, 發(fā)現(xiàn)Curator主要解決了三類問(wèn)題: 
  • 封裝ZooKeeper client與ZooKeeper server之間的連接處理;
  • 提供了一套Fluent風(fēng)格的操作API;
  • 提供ZooKeeper各種應(yīng)用場(chǎng)景(recipe, 比如共享鎖服務(wù), 集群領(lǐng)導(dǎo)選舉機(jī)制)的抽象封裝.


Curator列舉的ZooKeeper使用過(guò)程中的幾個(gè)問(wèn)題 
初始化連接的問(wèn)題: 在client與server之間握手建立連接的過(guò)程中, 如果握手失敗, 執(zhí)行所有的同步方法(比如create, getData等)將拋出異常 
自動(dòng)恢復(fù)(failover)的問(wèn)題: 當(dāng)client與一臺(tái)server的連接丟失,并試圖去連接另外一臺(tái)server時(shí), client將回到初始連接模式 
session過(guò)期的問(wèn)題: 在極端情況下, 出現(xiàn)ZooKeeper session過(guò)期, 客戶端需要自己去監(jiān)聽(tīng)該狀態(tài)并重新創(chuàng)建ZooKeeper實(shí)例 . 
對(duì)可恢復(fù)異常的處理:當(dāng)在server端創(chuàng)建一個(gè)有序ZNode, 而在將節(jié)點(diǎn)名返回給客戶端時(shí)崩潰, 此時(shí)client端拋出可恢復(fù)的異常, 用戶需要自己捕獲這些異常并進(jìn)行重試 
使用場(chǎng)景的問(wèn)題:Zookeeper提供了一些標(biāo)準(zhǔn)的使用場(chǎng)景支持, 但是ZooKeeper對(duì)這些功能的使用說(shuō)明文檔很少, 而且很容易用錯(cuò). 在一些極端場(chǎng)景下如何處理, zk并沒(méi)有給出詳細(xì)的文檔說(shuō)明. 比如共享鎖服務(wù), 當(dāng)服務(wù)器端創(chuàng)建臨時(shí)順序節(jié)點(diǎn)成功, 但是在客戶端接收到節(jié)點(diǎn)名之前掛掉了, 如果不能很好的處理這種情況, 將導(dǎo)致死鎖. 

Curator主要從以下幾個(gè)方面降低了zk使用的復(fù)雜性: 
重試機(jī)制:提供可插拔的重試機(jī)制, 它將給捕獲所有可恢復(fù)的異常配置一個(gè)重試策略, 并且內(nèi)部也提供了幾種標(biāo)準(zhǔn)的重試策略(比如指數(shù)補(bǔ)償). 
連接狀態(tài)監(jiān)控: Curator初始化之后會(huì)一直的對(duì)zk連接進(jìn)行監(jiān)聽(tīng), 一旦發(fā)現(xiàn)連接狀態(tài)發(fā)生變化, 將作出相應(yīng)的處理. 
zk客戶端實(shí)例管理:Curator對(duì)zk客戶端到server集群連接進(jìn)行管理. 并在需要的情況, 重建zk實(shí)例, 保證與zk集群的可靠連接 
各種使用場(chǎng)景支持:Curator實(shí)現(xiàn)zk支持的大部分使用場(chǎng)景支持(甚至包括zk自身不支持的場(chǎng)景), 這些實(shí)現(xiàn)都遵循了zk的最佳實(shí)踐, 并考慮了各種極端情況. 

Curator通過(guò)以上的處理, 讓用戶專注于自身的業(yè)務(wù)本身, 而無(wú)需花費(fèi)更多的精力在zk本身. 

Curator聲稱的一些亮點(diǎn): 

日志工具 
內(nèi)部采用SLF4J 來(lái)輸出日志 
采用驅(qū)動(dòng)器(driver)機(jī)制, 允許擴(kuò)展和定制日志和跟蹤處理 
提供了一個(gè)TracerDriver接口, 通過(guò)實(shí)現(xiàn)addTrace()和addCount()接口來(lái)集成用戶自己的跟蹤框架 

和Curator相比, 另一個(gè)ZooKeeper客戶端——zkClient(https://github.com/sgroschupf/zkclient)的不足之處: 
文檔幾乎沒(méi)有 
異常處理弱爆了(簡(jiǎn)單的拋出RuntimeException) 
重試處理太難用了 
沒(méi)有提供各種使用場(chǎng)景的實(shí)現(xiàn) 

對(duì)ZooKeeper自帶客戶端(ZooKeeper類)的"抱怨": 
只是一個(gè)底層實(shí)現(xiàn) 
要用需要自己寫大量的代碼 
很容易誤用 
需要自己處理連接丟失, 重試等 

Curator幾個(gè)組成部分 
  • Client: 是ZooKeeper客戶端的一個(gè)替代品, 提供了一些底層處理和相關(guān)的工具方法.
  • Framework: 用來(lái)簡(jiǎn)化ZooKeeper高級(jí)功能的使用, 并增加了一些新的功能, 比如管理到ZooKeeper集群的連接, 重試處理
  • Recipes: 實(shí)現(xiàn)了通用ZooKeeper的recipe, 該組件建立在Framework的基礎(chǔ)之上
  • Utilities:各種ZooKeeper的工具類
  • Errors: 異常處理, 連接, 恢復(fù)等.
  • Extensions: recipe擴(kuò)展


Client 
這是一個(gè)底層的API, 應(yīng)用方基本對(duì)這個(gè)可以無(wú)視, 最好直接從Curator Framework入手 
主要包括三部分: 
不間斷連接管理 
連接重試處理 

Retry Loop(循環(huán)重試) 
一種典型的用法: 
Java代碼  收藏代碼
  1. RetryLoop retryLoop = client.newRetryLoop();  
  2. while ( retryLoop.shouldContinue() )  
  3. {  
  4.    try  
  5.    {  
  6.        // perform your work  
  7.        ...  
  8.        // it's important to re-get the ZK instance as there may have been an error and the instance was re-created  
  9.        ZooKeeper      zk = client.getZookeeper();  
  10.   
  11.        retryLoop.markComplete();  
  12.    }  
  13.    catch ( Exception e )  
  14.    {  
  15.        retryLoop.takeException(e);  
  16.    }  
  17. }  

如果在操作過(guò)程中失敗, 且這種失敗是可重試的, 而且在允許的次數(shù)內(nèi), Curator將保證操作的最終完成. 

另一種使用Callable接口的重試做法: 
Java代碼  收藏代碼
  1. RetryLoop.callWithRetry(client, new Callable()  
  2. {  
  3.       @Override  
  4.       public Void call() throws Exception  
  5.       {  
  6.           // do your work here - it will get retried if needed  
  7.           return null;  
  8.       }  
  9. });  


重試策略 
RetryPolicy接口只有一個(gè)方法(以前版本有兩個(gè)方法): 
public boolean allowRetry(int retryCount, long elapsedTimeMs); 
在開(kāi)始重試之前, allowRetry方法被調(diào)用, 其參數(shù)將指定當(dāng)前重試次數(shù), 和操作已消耗時(shí)間. 如果允許, 將繼續(xù)重試, 否則拋出異常. 

Curator內(nèi)部實(shí)現(xiàn)的幾種重試策略: 
  • ExponentialBackoffRetry:重試指定的次數(shù), 且每一次重試之間停頓的時(shí)間逐漸增加.
  • RetryNTimes:指定最大重試次數(shù)的重試策略
  • RetryOneTime:僅重試一次
  • RetryUntilElapsed:一直重試直到達(dá)到規(guī)定的時(shí)間


Framework 
是ZooKeeper Client更高的抽象API 
自動(dòng)連接管理: 當(dāng)ZooKeeper客戶端內(nèi)部出現(xiàn)異常, 將自動(dòng)進(jìn)行重連或重試, 該過(guò)程對(duì)外幾乎完全透明 
更清晰的API: 簡(jiǎn)化了ZooKeeper原生的方法, 事件等, 提供流程的接口 

CuratorFrameworkFactory類提供了兩個(gè)方法, 一個(gè)工廠方法newClient, 一個(gè)構(gòu)建方法build. 使用工廠方法newClient可以創(chuàng)建一個(gè)默認(rèn)的實(shí)例, 而build構(gòu)建方法可以對(duì)實(shí)例進(jìn)行定制. 當(dāng)CuratorFramework實(shí)例構(gòu)建完成, 緊接著調(diào)用start()方法, 在應(yīng)用結(jié)束的時(shí)候, 需要調(diào)用close()方法.  CuratorFramework是線程安全的. 在一個(gè)應(yīng)用中可以共享同一個(gè)zk集群的CuratorFramework. 

CuratorFramework API采用了連貫風(fēng)格的接口(Fluent Interface). 所有的操作一律返回構(gòu)建器, 當(dāng)所有元素加在一起之后, 整個(gè)方法看起來(lái)就像一個(gè)完整的句子. 比如下面的操作: 
Java代碼  收藏代碼
  1. client.create().forPath("/head"new byte[0]);  
  2. client.delete().inBackground().forPath("/head");  
  3. client.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/head/child"new byte[0]);  
  4. client.getData().watched().inBackground().forPath("/test");  


方法說(shuō)明: 
  • create(): 發(fā)起一個(gè)create操作. 可以組合其他方法 (比如mode 或background) 最后以forPath()方法結(jié)尾
  • delete(): 發(fā)起一個(gè)刪除操作. 可以組合其他方法(version 或background) 最后以forPath()方法結(jié)尾
  • checkExists(): 發(fā)起一個(gè)檢查ZNode 是否存在的操作. 可以組合其他方法(watch 或background) 最后以forPath()方法結(jié)尾
  • getData(): 發(fā)起一個(gè)獲取ZNode數(shù)據(jù)的操作. 可以組合其他方法(watch, background 或get stat) 最后以forPath()方法結(jié)尾
  • setData(): 發(fā)起一個(gè)設(shè)置ZNode數(shù)據(jù)的操作. 可以組合其他方法(version 或background) 最后以forPath()方法結(jié)尾
  • getChildren(): 發(fā)起一個(gè)獲取ZNode子節(jié)點(diǎn)的操作. 可以組合其他方法(watch, background 或get stat) 最后以forPath()方法結(jié)尾
  • inTransaction(): 發(fā)起一個(gè)ZooKeeper事務(wù). 可以組合create, setData, check, 和/或delete 為一個(gè)操作, 然后commit() 提交


通知(Notification) 
Curator的相關(guān)代碼已經(jīng)更新了, 里面的接口已經(jīng)由ClientListener改成CuratorListener了, 而且接口中去掉了clientCloseDueToError方法. 只有一個(gè)方法: 
eventReceived()            當(dāng)一個(gè)后臺(tái)操作完成或者指定的watch被觸發(fā)時(shí)該方法被調(diào)用 

UnhandledErrorListener接口用來(lái)對(duì)異常進(jìn)行處理. 

CuratorEvent(在以前版本為ClientEvent)是對(duì)各種操作觸發(fā)相關(guān)事件對(duì)象(POJO)的一個(gè)完整封裝, 而事件對(duì)象的內(nèi)容跟事件類型相關(guān), 下面是對(duì)應(yīng)關(guān)系: 
CREATEgetResultCode() and getPath()
DELETEgetResultCode() and getPath()
EXISTSgetResultCode(), getPath() and getStat()
GET_DATAgetResultCode(), getPath(), getStat() and getData()
SET_DATAgetResultCode(), getPath() and getStat()
CHILDRENgetResultCode(), getPath(), getStat(), getChildren()
WATCHEDgetWatchedEvent()


名稱空間(Namespace) 
因?yàn)橐粋€(gè)zk集群會(huì)被多個(gè)應(yīng)用共享, 為了避免各個(gè)應(yīng)用的zk patch沖突, Curator Framework內(nèi)部會(huì)給每一個(gè)Curator Framework實(shí)例分配一個(gè)namespace(可選). 這樣你在create ZNode的時(shí)候都會(huì)自動(dòng)加上這個(gè)namespace作為這個(gè)node path的root. 使用代碼如下: 

Java代碼  收藏代碼
  1. CuratorFramework    client = CuratorFrameworkFactory.builder().namespace("MyApp") ... build();  
  2.  …  
  3. client.create().forPath("/test", data);  
  4. // node was actually written to: "/MyApp/test"  



Recipe 

Curator實(shí)現(xiàn)ZooKeeper的所有recipe(除了兩段提交) 
選舉 
集群領(lǐng)導(dǎo)選舉(leader election) 

鎖服務(wù) 
共享鎖: 全局同步分布式鎖, 同一時(shí)間兩臺(tái)機(jī)器只有一臺(tái)能獲得同一把鎖. 
共享讀寫鎖: 用于分布式的讀寫互斥處理, 同時(shí)生成兩個(gè)鎖:一個(gè)讀鎖, 一個(gè)寫鎖, 讀鎖能被多個(gè)應(yīng)用持有, 而寫鎖只能一個(gè)獨(dú)占, 當(dāng)寫鎖未被持有時(shí), 多個(gè)讀鎖持有者可以同時(shí)進(jìn)行讀操作 
共享信號(hào)量: 在分布式系統(tǒng)中的各個(gè)JVM使用同一個(gè)zk lock path, 該path將跟一個(gè)給定數(shù)量的租約(lease)相關(guān)聯(lián), 然后各個(gè)應(yīng)用根據(jù)請(qǐng)求順序獲得對(duì)應(yīng)的lease, 相對(duì)來(lái)說(shuō), 這是最公平的鎖服務(wù)使用方式. 
多共享鎖:內(nèi)部構(gòu)件多個(gè)共享鎖(會(huì)跟一個(gè)znode path關(guān)聯(lián)), 在acquire()過(guò)程中, 執(zhí)行所有共享鎖的acquire()方法, 如果中間出現(xiàn)一個(gè)失敗, 則將釋放所有已require的共享鎖; 執(zhí)行release()方法時(shí), 則執(zhí)行內(nèi)部多個(gè)共享鎖的release方法(如果出現(xiàn)失敗將忽略) 

隊(duì)列(Queue) 
分布式隊(duì)列:采用持久順序zk node來(lái)實(shí)現(xiàn)FIFO隊(duì)列, 如果有多個(gè)消費(fèi)者, 可以使用LeaderSelector來(lái)保證隊(duì)列的消費(fèi)者順序 
分布式優(yōu)先隊(duì)列: 優(yōu)先隊(duì)列的分布式版本 
BlockingQueueConsumer: JDK阻塞隊(duì)列的分布式版本 

關(guān)卡(Barrier) 
分布式關(guān)卡:一堆客戶端去處理一堆任務(wù), 只有所有的客戶端都執(zhí)行完, 所有客戶端才能繼續(xù)往下處理 
雙分布式關(guān)卡:同時(shí)開(kāi)始, 同時(shí)結(jié)束 

計(jì)數(shù)器(Counter) 
共享計(jì)數(shù)器:所有客戶端監(jiān)聽(tīng)同一個(gè)znode path, 并共享一個(gè)最新的integer計(jì)數(shù)值 
分布式AtomicLong(AtomicInteger): AtomicXxx的分布式版本, 先采用樂(lè)觀鎖更新, 若失敗再采用互斥鎖更新, 可以配置重試策略來(lái)處理重試 

工具類 

Path Cache 
Path Cache用于監(jiān)聽(tīng)ZNode的子節(jié)點(diǎn)的變化, 當(dāng)add, update, remove子節(jié)點(diǎn)時(shí)將改變Path Cache state, 同時(shí)返回所有子節(jié)點(diǎn)的data和state. 
Curator中采用了PathChildrenCache類來(lái)處理Path Cache, 狀態(tài)的變化則采用PathChildrenCacheListener來(lái)監(jiān)聽(tīng).
相關(guān)用法參見(jiàn)TestPathChildrenCache測(cè)試類 

注意: 當(dāng)zk server的數(shù)據(jù)發(fā)生變化, zk client會(huì)出現(xiàn)不一致, 這個(gè)需要通過(guò)版本號(hào)來(lái)識(shí)別這種狀態(tài)的變化 

Test Server 
用來(lái)在測(cè)試中模擬一個(gè)本地進(jìn)程內(nèi)ZooKeeper Server. 

Test Cluster 
用來(lái)在測(cè)試中模擬一個(gè)ZooKeeper Server集群 

ZKPaths工具類 
提供了和ZNode相關(guān)的path處理工具方法: 
   
  • getNodeFromPath: 根據(jù)給定path獲取node name. i.e. "/one/two/three" -> "three"
  •     mkdirs: 根據(jù)給定路徑遞歸創(chuàng)建所有node
  •     getSortedChildren: 根據(jù)給定路徑, 返回一個(gè)按序列號(hào)排序的子節(jié)點(diǎn)列表
  •     makePath: 根據(jù)給定的path和子節(jié)點(diǎn)名, 創(chuàng)建一個(gè)完整path


EnsurePath工具類 

直接看例子, 具體的說(shuō)就是調(diào)用多次, 只會(huì)執(zhí)行一次創(chuàng)建節(jié)點(diǎn)操作. 

Java代碼  收藏代碼
  1. EnsurePath       ensurePath = new EnsurePath(aFullPathToEnsure);  
  2. ...  
  3. String           nodePath = aFullPathToEnsure + "/foo";  
  4. ensurePath.ensure(zk);   // first time syncs and creates if needed  
  5. zk.create(nodePath, ...);  
  6. ...  
  7. ensurePath.ensure(zk);   // subsequent times are NOPs  
  8. zk.create(nodePath, ...);  


Notification事件處理 
Curator對(duì)ZooKeeper的事件Watcher進(jìn)行了封裝處理, 然后實(shí)現(xiàn)了一套監(jiān)聽(tīng)機(jī)制. 提供了幾個(gè)監(jiān)聽(tīng)接口用來(lái)處理ZooKeeper連接狀態(tài)的變化 
當(dāng)連接出現(xiàn)異常, 將通過(guò)ConnectionStateListener接口進(jìn)行監(jiān)聽(tīng), 并進(jìn)行相應(yīng)的處理, 這些狀態(tài)變化包括: 
  • 暫停(SUSPENDED): 當(dāng)連接丟失, 將暫停所有操作, 直到連接重新建立, 如果在規(guī)定時(shí)間內(nèi)無(wú)法建立連接, 將觸發(fā)LOST通知
  • 重連(RECONNECTED): 連接丟失, 執(zhí)行重連時(shí), 將觸發(fā)該通知
  • 丟失(LOST): 連接超時(shí)時(shí), 將觸發(fā)該通知


從com.netflix.curator.framework.imps.CuratorFrameworkImpl.validateConnection(CuratorEvent)方法中我們可以知道, Curator分別將ZooKeeper的Disconnected, Expired, SyncConnected三種狀態(tài)轉(zhuǎn)換成上面三種狀態(tài). 

參考 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多