Програми Java часто мають різні конфігурації. Наприклад, адресаа та порт підключення. Наприклад, це могло б виглядати так, якби використовували клас Properties :
І цього начебто достатньо, т.к. ми можемо Properties отримати із файлу. І наче у нас все на одній машині вживається добре. Але уявіть, що наша система починає складатися із різних систем, які розділені між собою? Така система ще називається розподіленою (Distributed Systems). У вікіпедії можна знайти таке визначення: Розподілені системи - це системи, компоненти які розташовані на різних мережевих комп'ютерах, які спілкуються між собою та координують свої дії обмінюючись одна з одною повідомленнями. Можна поглянути на таку схему:
За такого підходу єдина система розділена на компоненти. Конфігурування – окремий загальний компонент. Кожен із інших компонентів виступає у ролі клієнта для компонента конфігурування. Такий випадок називається " Розподілена конфігурація ". Існує безліч різних реалізацій розподіленої конфігурації. І в сьогоднішньому огляді пропоную познайомитись із однією з них, яка називається Zookeeper.
Zookeeper
Шлях до знайомства з Zookeeper починається з їхнього офіційного сайту: zookeeper.apache.org На офіційному сайті необхідно перейти в розділ " Download ". У цьому розділі завантажуємо архів у форматі .tar.gz, наприклад "zookeeper-3.4.13.tar.gz". tar – це формат архіву, традиційний для Unit систем. gz означає, що для стиснення архіву використовується gzip. Якщо ми працюємо на Windows машині, нас це не повинно бентежити. Більшість сучасних архіваторів (наприклад, 7-zip), чудово вміють з ними працювати і на Windows. Витягнемо вміст у якийсь каталог. Заодно побачимо різницю - на диску у видобутому стані воно займатиме приблизно 60 мегабайт, а ми завантажували архів розміром близько 35 мегабайт. Як видно, стиск дійсно працює. Тепер потрібно запустити Zookeeper. Взагалі Zookeeper є свого роду сервером. Zookeeper може бути запущений в одному з двох режимів: Standalone або Replicated . Розглянемо найпростіший варіант, він перший варіант — Standalone mode. Щоб Zookeper запустився, йому потрібний файл конфігурації. Тому, створимо його тут: [КаталогРаспаковкиZookeeper]/conf/zoo.cfg. Для Windows скористаємося рекомендацією з Medium: " Installing Apache ZooKeeper on Windows". Зміст конфігураційного файлу буде приблизно наступним:
Додамо змінну середовища оточення ZOOKEEPER_HOME, що містить шлях до кореневого каталогу zookeper (як в інструкції на medium), а також додамо змінну середовища оточення PATH наступний фрагмент: Так само каталог, вказаний в dataDir, повинен існувати, інакше Zookeeper не зможе ;%ZOOKEEPER_HOME%\bin; запустити сервер. Тепер ми можемо сміливо запускати сервер за допомогою команди zkServer. Завдяки тому, що каталог Zookeeper був доданий до змінного середовища оточення path ми можемо викликати команди Zookeper звідки завгодно, а не тільки з каталогу bin.
ZNode
Як сказано в " Zookeeper Overview ", дані в Zookeper представлені у вигляді ZNode (вузлів), які об'єднані в деревоподібну структуру. Тобто кожен ZNode може містити дані та мати дочірні ZNode. Докладніше про організацію ZNode можна прочитати в документації Zookeeper: " Data model and the hierarchical namespace ". Для роботи з Zookeeper та ZNode скористаємося Zookeeper CLI (Command Line interface – інтерфейс командного рядка). Раніше ми запустабо сервер за допомогою команди zkServer. Тепер, для підключення виконаємо zkCli.cmd -server 127.0.0.1:2181 При успішному виконанні буде створена сесія підключення до Zookeeper і ми побачимо приблизно такий висновок:
Цікаво, що навіть одразу після встановлення Zookeeper вже має ZNode. Має він наступний шлях:/zookeeper/quota
Це звані " квоти " . Як сказано в " Apache ZooKeeper Essentials ", кожен ZNode може мати асоційовану з ним квоту, що обмежує збережені дані. Може бути вказано обмеження кількості znode і обсяг збережених даних. Якщо це обмеження перевищено, то операції з ZNode не скасовується, але буде отримано попередження про перевищення ліміту. Про ZNode рекомендується прочитати в " ZooKeeper Programmer's Guide: ZNodes ". Декілька прикладів від туди, як можна працювати з ZNode:
Хочеться відзначити також, що ZNode бувають різні. Звичайні ZNode (якщо не вказати додаткові прапори) є типом " persistent ". Є ZNode типу " Ephemeral Node ". Такі ZNode існують лише на час існування сесії підключення до Zookeeper, в рамках якої вони створювалися. Є ZNode типу " Sequence Node ". До таких ZNode додається номер із послідовності, щоб гарантувати унікальність. Sequence Node може бути як persistent, і ephemeral. Про ZNode так само рекомендується невелика довідкова інформація тут: " Zookeeper ZNodes - Characteristics & Example ".
ZNode Watcher
Хотілося б поговорити про спостерігачів (watchers). Докладно про них написано в документації Zookeeper'а: " ZooKeeper Watches ". Якщо коротко, то вотчер – це такий одноразовий тригер, який спрацьовує на певну подію. Отримуючи дані, виконуючи операції getData(), getChildren() або exists(), ми можемо створити тригер як додаткову дію. Zookeeper забезпечує порядок обробки event. Крім того, в документації зазначено, що перш ніж ми зможемо побачити нове значення ZNode, ми побачимо event про зміну старого значення на нове. Докладніше про Watcher'ів можна прочитати тут: " ZooKeeper Watches - Features & Guarantees ". Для того щоб це спробувати, знову скористаємося CLI: Припустимо, у нас є деякий ZNode зі значенням, де ми зберігаємо статус деякого сервісу:
[zk:127.0.0.1:2181(CONNECTED)0] create /services/service1/status stopped
Created/services/service1/status
[zk:127.0.0.1:2181(CONNECTED)1] get /services/service1/status [watch]
stopped
Тепер, якщо дані /services/service1/statusзміниться, то відпрацює наш одноразовий тригер:
Цікаво, що при підключенні до Zookeeper'у ми також бачимо, як відпрацьовує вотчер:
SyncConnected є однією з можливих подій Zookeper. Докладніше про нього можна переглянути в описі API.
Zookeeper та Java
Тепер у нас є деяке базове уявлення про те, що може Zookeeper. Давайте тепер із ним попрацюємо через Java, а не через CLI. І для цього нам знадобиться Java додаток, на якому ми побачимо, як же з Zookeeper'ом працювати. Для створення програми скористаємося системою складання проектів Gradle . За допомогою " Gradle Build Init plugin " виконаємо створення проекту. Для цього виконаємо команду:gradle init --type java-application Якщо Gradle нас буде запитувати уточнюючі питання, то залишимо значення за замовчуванням (просто натискаємо Enter). Тепер відкриємо білд-скрипт, тобто. файл build.gradle. У ньому опис того, з чого влаштований наш проект і від яких артефактів (бібліотек, фреймворків) залежить. Т.к. ми хочемо використовувати Zookeeper, треба додати його. Тому, додамо в блок залежності залежність від Zookeeper'а:
Докладніше про Gradle можна прочитати в огляді: " Коротке знайомство з Gradle ". Отже, ми маємо Java проект, до нього ми підключабо бібліотеку Zookeeper'а. Давайте тепер щось напишемо. Як ми пам'ятаємо, за допомогою CLI ми підключалися приблизно так: zkCli.cmd -server 127.0.0.1:2181 Давайте в класі App в main методі оголосимо атрибут "сервер":
String server ="127.0.0.1:2181";
Підключення – дія не миттєва. Нам доведеться якось у головному потоці виконання програми чекати, коли відбудеться підключення. Тому нам знадобиться лок. Оголосимо його нижче:
Object lock =newObject();
Тепер нам потрібний хтось, хто скаже, що підключення встановлено. Як ми пам'ятаємо, коли ми це робабо через CLI, у нас спрацьовував вотчер. Так ось в Java коді все так само. Наш вотчер виводитиме повідомлення про успішне виконання і повідомлятиме про це всіх, хто чекає через лок. Напишемо вотчер:
Watcher connectionWatcher =newWatcher(){publicvoidprocess(WatchedEvent we){if(we.getState()==Event.KeeperState.SyncConnected){System.out.println("Connected to Zookeeper in "+Thread.currentThread().getName());synchronized(lock){
lock.notifyAll();}}}};
Тепер допишемо підключення до сервера zooKeeper'а:
int sessionTimeout =2000;ZooKeeper zooKeeper =null;synchronized(lock){
zooKeeper =newZooKeeper(server, sessionTimeout, connectionWatcher);
lock.wait();}
Тут все просто. При виконанні main методу в головному потоці програми ми захоплюємо lock і запитуємо підключення до zookeeper'у. При цьому ми відпускаємо лок і чекаємо, поки хтось інший не захопить лок і не повідомить нас, що можна продовжувати. Коли підключення буде встановлено, то спрацює вічер. Він перевірить, що настала подія - SyncConnected (як ми пам'ятаємо, саме її ловив вотчер через CLI), і тоді напише повідомлення. Далі ми захоплюємо lock (т.к. раніше головний потік його відпустив) і повідомляємо всі потоки, що чекають lock, що можна продовжувати. Потік обробки події виходить із synchronized блоку, тим самим звільняючи lock. Головний потік отримав повідомлення та дочекавшись звільнення lock продовжує виконання, т.к. поки не отримає lock, то він не зможе вийти з synchronized блоку та продовжити роботу. Таким чином, використовуючи багатопотоковість і Zookeeper API ми можемо виконувати різні дії. Zookeeper API набагато ширше, ніж дозволяє використовувати CLI. Наприклад:
// створення нового узлаString znodePath ="/zookeepernode2";List<ACL> acls =ZooDefs.Ids.OPEN_ACL_UNSAFE;if(zooKeeper.exists(znodePath,false)==null){
zooKeeper.create(znodePath,"data".getBytes(), acls,CreateMode.PERSISTENT);}// Получение данных из узлаbyte[] data = zooKeeper.getData(znodePath,null,null);System.out.println("Result: "+newString(data,"UTF-8"));
Як видно, під час створення вузла ми можемо налаштувати ACL. Це ще одна важлива особливість. ACL – це дозволи, які поширюються на дії з ZNode. Налаштувань багато, тому за подробицями рекомендую звернутися до офіційної документації: " Zookeeper ACL Permissions ".
Висновок
Навіщо ми це прочитали? Тому що Zookeeper використовується і в інших затребуваних технологіях. Наприклад, Apache Kafka вимагає Zookeeper, про що можна прочитати в " Kafka Quick Start Guide ". Так само використовується в NOSQL базі даних HBase, про що можна докладніше прочитати в їх " HBase Quickstart Guide ". Насправді багато інших проектів використовують Zookeeper. Частина з них наведена у списку у " Використання Zookeeper у реальному світі ". Сподіваюся, на запитання "навіщо" я відповів. Найголовніше питання тепер: "Що далі?" По-перше, на тему Apache Zookeeper можна почитати такі книги:
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ