Механизм watcher в Zookeeper можно разделить на четыре процесса:
- Клиент регистрирует watcher.
- Сервер обрабатывает watcher.
- Сервер генерирует событие watcher.
- Клиент выполняет обратный вызов watcher.
Существует три способа регистрации watcher клиентом. Клиентский API можно вызвать через getData, exists и getChildren соответственно. Используя Maven-проект, созданный в предыдущей главе, создайте класс WatcherDemo и на примере метода exists проиллюстрируйте принцип.
Пример
static ZooKeeper zooKeeper;
static {
try {
zooKeeper = new ZooKeeper("192.168.3.39:2181", 4000,new WatcherDemo());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void process(WatchedEvent event) {
System.out.println("eventType:"+event.getType());
if(event.getType()==Event.EventType.NodeDataChanged){
try {
zooKeeper.exists(event.getPath(),true);
} catch (KeeperException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException, KeeperException, InterruptedException {
String path="/watcher";
if(zooKeeper.exists(path,false)==null) {
zooKeeper.create("/watcher", "0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
}
Thread.sleep(1000);
System.out.println("-----------");
//true указывает на использование наблюдателя, настроенного в экземпляре Zookeeper
Stat stat=zooKeeper.exists(path,true);
System.in.read();
}
}
После запуска программы в консоли отображается:

Теперь запустите командный терминал Zookeeper, просмотрите и удалитеwatcherузел:

Вывод консоли IDE: событие удаления узла было инициировано:

Клиент отправляет запросы серверу через долговременное TCP-соединение для установления сетевого канала. По умолчанию базовая реализация использует Java NIO, также можно настроить использование Netty.

Блок-схема регистрации событий прослушивания watcher:

1. Клиент отправляет запрос уведомления о событии
Когда класс Zookeeper вызывает метод exists, создание слушателя событий инкапсулируется в объект запроса с атрибутом watch, установленным в true. После того как сервер возвращает ответ, событие слушателя инкапсулируется в класс ZKWatchManager клиента.

2. Сервер обрабатывает запрос события watcher
Класс NIOServerCnxn на стороне сервера используется для обработки запросов, отправленных клиентом, в конечном итоге вызывая FinalRequestProcessor, где фрагмент исходного кода добавляет событие watcher, отправленное клиентом:

Затем он входит в метод statNode, добавляет событие watcher в методе класса DataTree и сохраняет его в watchTable и watchTable класса WatchManager.


3. Сервер запускает поток событий watcher:
Если отслеживаемый узел на сервере получает запрос транзакции, во время обработки запроса сервером вызывается следующий код в методе processRequest класса FinalRequestProcessor:

Цепочка вызовов удаления в конечном итоге достигает фрагмента кода триггера для ветви удаления узла в классе DataTree:

Войдите в метод triggerWatch класса WatchManager:

Продолжая трассировку в NIOServerCnxn, он создаёт объект ReplyHeader с xid равным -1 и zxid равным -1, а затем вызывает метод sendResonpe.

4. Клиентский обратный вызов для события watcher
Метод readResponse класса SendThread клиента получает уведомление о событии, инициированное сервером, входит в поток xid = -1 и обрабатывает Event.


Скачать исходный код для этой главы
Скачать