Zookeeper隐藏通道和羊群效应
隱藏通道
ZooKeeper客戶端總是會觀察到相同的更新順序,即使它們連接到不同的服務端上。但是客戶端可能是在不同時間觀察到了更新,如果他們還在ZooKeeper以外通信,這種差異就會更加明顯。讓我們考慮以下場景:
?
客戶端c1通過TCP的直接連接告知客戶端c2,/z節點狀態發生了變化
?
客戶端c2讀取/z節點的狀態,但是在c1更新之前就觀察到了這個狀態
我們稱之為隱藏通道(hiddenchannel),因為ZooKeeper并不知道客戶端之間額外的通信。現在c2 獲得了過期數據,圖4-2描述了這種情況:
?
為了避免讀取到過去的數據,我們建議應用程序使用ZooKeeper進行所有涉及ZooKeeper狀態的通信。例如,為了避免剛剛描述的場景,c2 可以在/z節點設置監視點來代替從c1 直接接收消息,通過監視點,c2就可以知道/z節點的變化,從而消除隱藏通道的問題。
?
在這里Zookeeper提供了sync方法,該方法會刷新調用sync的服務端與群首之間的通道,這樣就能獲取所有的數據變化信息。使用方式如下:
try {ZooKeeper zk = new ZooKeeper("127.0.0.1:2181", 3000, null);VoidCallback cb = new VoidCallback() {@Overridepublic void processResult(int rc, String path, Object ctx) {// ......}};zk.sync("/sync_node", cb, "同步");zk.getData("/sync_node", null, null); } catch (IOException | KeeperException | InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace(); }羊群效應
?
有一個問題需要注意,當變化發生時,ZooKeeper會觸發一個特定的znode節點的變化導致的所有監視點的集合。如果有1000個客戶端通過exists操作監視這個znode節點,那么當znode節點創建后就會發送1000個通知,因而被監視的znode節點的一個變化會產生一個尖峰的通知,該尖峰可能帶來影響,例如,在尖峰時刻提交的操作延遲。可能的話,我們建議在使用ZooKeeper時,避免在一個特定節點設置大量的監視點,最好是每次在特定的znode節點上,只有少量的客戶端設置監視點,理想情況下最多只設置一個。
解決該問題的方法并不適用于所有的情況,但在以下情況下可能很有用。假設有n個客戶端爭相獲取一個鎖(例如,主節點鎖)。為了獲取鎖,一個進程試著創建/lock節點,如果znode節點存在了,客戶端就會監視這個znode節點的刪除事件。當/lock被刪除時,所有監視/lock節點的客戶端收到通知。另一個不同的方法,讓客戶端創建一個有序的節點/lock/lock-,回憶之前討論的有序節點,ZooKeeper在這個znode節點上自動添加一個序列號,成為/lock/lock-xxx,其中xxx為序列號。我們可以使用這個序列號來確定哪個客戶端獲得鎖,通過判斷/lock下的所有創建的子節點的最小序列號。在該方案中,客戶端通過/getChildren方法來獲取所有/lock下的子節點,并判斷自己創建的節點是否是最小的序列號。如果客戶端創建的節點不是最小序列號,就根據序列號確定序列,并在前一個節點上設置監視點。例如:假設我們有三個節點:/lock/lock-001、/lock/lock-002和/lock/lock-003,在這個例子中情況如下:
?
這樣,每個節點上設置的監視點只有最多一個客戶端。
?
另一方面需要注意的問題,就是當服務端一側通過監視點產生的狀態變化。設置一個監視點需要在服務端創建一個Watcher對象,根據YourKit的分析工具所分析,設置一個監視點會使服務端的監視點管理器的內存消耗上增加大約250到300個字節,設置非常多的監視點意味著監視點管理器會消耗大量的服務器內存。例如,如果存在一百萬個監視點,估計會消耗0.3GB的內存,因此,開發者必須時刻注意設置的監視點數量。
參考
《Zookeeper-分布式過程協同技術詳解》
?
總結
以上是生活随笔為你收集整理的Zookeeper隐藏通道和羊群效应的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: colorbox去除close关闭按钮,
- 下一篇: atr指标 java算法_关于股指期货的