一、通過一個例子引出監視的概念
- ZooKeeper通常以遠程服務的⽅式被訪問,如果每次訪問znode時,客戶端都需要獲得節點中的內容,這樣的代價就⾮常⼤。因爲這樣會導致更⾼的延遲,⽽且ZooKeeper需要做更多的操作
演示說明
- 考慮下圖的例⼦,第⼆次調⽤getChildren/tasks返回了相同的值(⼀個空的集合),其實是沒有必要的
- 這是⼀個常見的輪詢問題
- 爲了替換客戶端的輪詢,我們選擇了基於通知(notification)的機制:
- 客戶端向ZooKeeper註冊需要接收通知的znode,通過對znode設置監視點(watch)來接收通知
- 如下圖所示,當節點/tasks發⽣變化時,客戶端會收到⼀個通知,並從ZooKeeper讀取⼀個新值
二、監視相關API
printwatches
- 功能:開關,用來是否打印監視(watchers)信息
- 格式:
printwatches on|off
- 演示案例:
printwatches on
get
- get有一個-w選項,用來在獲取路徑的數據時同時添加一個監視
- 備註:要將printwatches設置爲on纔可以使用
- 演示案例:
# 創建一個節點 create /latest_producer_id_block printwatches on # 添加監視 get -w /latest_producer_id_block # 此處爲了演示監視,我們刪除該節點,會有信息輸出 delete /latest_producer_id_block
ls
- 與get類似,ls頁有一個-w選項,用來在獲取路徑的數據時同時添加一個監視
- 備註:要將printwatches設置爲on纔可以使用
- 演示案例:
printwatches on # 對/zookeeper添加監視 ls -w /zookeeper
addWatch
- 功能:對一個節點添加監視
- 格式:
addWatch [-m mode] path
- 選項:
- -m:可選的值有PERSISTENT,PERSISTENT_RECURSIVE。默認爲PERSISTENT_RECURSIVE
removewatches
- 功能:刪除節點下的監視
- 格式:
removewatches path [-c|-d|-a] [-l]
- 演示案例:
create /test_node # 添加監視 get -w /test_node # 移除監視 removewatches /test_node
三、監視相關注意事項
監視點的單次觸發機制
- 監視點是⼀個單次觸發的操作,意思爲監視點只觸發一次,觸發之後就消失了
- 爲了接收多個通知,客戶端必須在每次通知後設置⼀個新的監視點
監視點更新前的變更
- 因爲監視點是單次觸發操作,在單次觸發之後我們需要重新設置監視點。但是在“監視點被觸發”到“重新設置監視點”之間可能有其他新的數據加入到監視點中,因此我們需要解決這些問題
- 場景如下,假設事件按以下順序發生:
- 1.客戶端c1設置監視點來監控/tasks數據的變化
- 2.客戶端c1連接後,向/tasks中添加了⼀個新的任務
- 3.客戶端c1接收通知
- 4.客戶端c1設置新的監視點,在設置完成前,第三個客戶端c3連接後, 向/tasks中添加了⼀個新的任務
- 因爲客戶端c1在設置該監視點之前,該監視點已經被其他客戶端更新了,因此c1在重新設置監視點之前需要讀取節點/tasks的狀態,通過在設置監視點前讀取ZooKeeper的狀態並更新狀態
監視變更的順序建議
- 通知機制的⼀個重要保障是(是建議而不是強制要求):對同⼀個znode的操作,先向客戶端傳送通知,等所有的通知都結束之後再對該節點進⾏變更
- 場景分析:
- 客戶端對⼀個znode設置了監視點
- 之後該znode發⽣了兩個連續更新(不是同時到達的)
- 第⼀次更新後,第二次更新前,客戶端認爲節點發生改變了,立馬就去讀取數據
- 第二次更新結束之後,客戶端丟失了這部分更新的數據
- 我們認爲主要特性在於通知機制阻⽌了客戶端所觀察的更新順序。雖然ZooKeeper的狀態變化傳播給某些客戶端時更慢,但我們保障客戶端以全局的順序來觀察ZooKeeper的狀態
監視點的類型
- ZooKeeper可以定義不同類型的通知,這依賴於設置監視點對應的通知類型
- 客戶端可以設置多種監視點,如監控znode的數據變化、監控znode⼦節點的變化、監控znode的創建或刪除
- 爲了設置監視點,可以使⽤任何API中的調⽤來讀取ZooKeeper的狀態,在調⽤這些API時,傳⼊⼀個watcher對象或使⽤默認的watcher。後面的“主從模式例子的實現”文章,及“處理狀態變更”中會以主從模式的例⼦來展開討論,我們將深⼊研究如何使⽤該機制
注意:誰來管理我的緩存
- 如果不讓客戶端來管理其擁有的ZooKeeper數據的緩存,我們不得不讓ZooKeeper來管理這些應用程序的緩存。但是,這樣會導致ZooKeeper的設計更加複雜
- 事實上,如果讓ZooKeeper管理緩存失效,可能會導致ZooKeeper在運⾏時,停滯在等待客戶端確認⼀個緩存失效的請求上,因爲在進⾏所有的寫操作前,需要確認所有的緩存數據是否已經失效