Механизм watcher в Zookeeper можно разделить на четыре процесса:

  • Клиент регистрирует watcher.
  • Сервер обрабатывает watcher.
  • Сервер генерирует событие watcher.
  • Клиент выполняет обратный вызов watcher.

Существует три способа регистрации watcher клиентом. Клиентский API можно вызвать через getData, exists и getChildren соответственно. Используя Maven-проект, созданный в предыдущей главе, создайте класс WatcherDemo и на примере метода exists проиллюстрируйте принцип.

Пример

public class WatcherDemo implements Watcher {
    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.

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

Скачать