Apache Ignite Zero Deployment: як Zero?

Apache Ignite Zero Deployment: як Zero?

Ми – відділ розвитку технологій роздрібної мережі. Якось керівництво поставило завдання прискорити об'ємні обчислення за рахунок використання Apache Ignite у зв'язці з MSSQL, показало сайт із чудовими ілюстраціями та прикладами Java-коду. На сайті одразу сподобався Zero Deployment, опис якого обіцяє чудеса: ви не маєте manually deploy your Java or Scala code on each node in the grid and re-deploy it each time it changes. По ходу роботи виявилося, що Zero Deployment має специфіку використання, особливостями якої я хочу поділитися. Під катом роздуми та подробиці реалізації.

1. Постановка задачі

Суть завдання у наступному. Є довідник точок продажу SalesPoint та довідник товарів Sku (Stock Keeping Unit). Точка продажу має атрибут «типМагазина» зі значеннями «малий» та «великий». До кожної точки продажу підключається (завантажується із СУБД) асортимент (список товарів точки продажу) та подається інформація про те, що з вказаної дати вказаний товар
виключається з асортименту або додається до асортименту.

Потрібно організувати партиціонований кеш точок продажу та зберігати в ньому інформацію про підключені товари на місяць наперед. Сумісність із бойовою системою вимагає від клієнтського вузла Ignite завантажувати дані, обчислювати агрегат виду (типМагазина, кодТовара, день, число_точок_продажів) і вивантажувати його назад у СУБД.

2. Вивчення літератури

Досвіду поки що немає, тож починаю танцювати від грубки. Тобто з огляду на публікації.

Стаття 2016 року Знайомство з Apache Ignite: перші кроки містить посилання на документацію проекту Apache Ignite і заодно закид у невиразності цієї документації. Перечитав кілька разів, ясність не настає. Звертаюся до офіційного туторіалу починаємо, Який
оптимістично обіцяє "You'll be up and running in a jiffy!". Розбираюсь із налаштуваннями змінних середовища, дивлюся два відео Apache Ignite Essentials, для мого конкретного завдання вони виявилися не дуже корисними. Успішно запускаю Ignite з командного рядка зі стандартним файлом «example-ignite.xml», збираю перший додаток Compute Application за допомогою Maven. Додаток працює та використовує Zero Deployment, яка краса!

Читаю далі, а там приклад одразу використовує affinityKey (створений раніше через SQL-запит), та ще й застосовується загадковий BinaryObject:

IgniteCache<BinaryObject, BinaryObject> people 
        = ignite.cache("Person").withKeepBinary(); 

Почитав трохи: бінарний формат - щось на зразок рефлексії, доступ до полів об'єкта на ім'я. Може читати значення поля без десеріалізації об'єкта (економія пам'яті). Але для чого замість Person використовується BinaryObject, адже є Zero Deployment? Навіщо IgniteCache перекладається в IgniteCache ? Поки що неясно.

Переробляю Compute Application під власний випадок. Первинний ключ довідника точок продажу в MSSQL визначений як [id] [int] NOT NULL, створюю кеш за аналогією

IgniteCache<Integer, SalesPoint> salesPointCache=ignite.cache("spCache")

У XML-конфізі вказую, що кеш партиціонований

<bean class="org.apache.ignite.configuration.CacheConfiguration">
    <property name="name" value="spCache"/>
    <property name="cacheMode" value="PARTITIONED"/>
</bean>

Партиціонування за точками продажів передбачає, що необхідний агрегат буде побудований на кожному вузлі кластера для записів salesPointCache, що є там, після чого клієнтський вузол виконає підсумкове підсумовування.

Читаю туторіал First Ignite Compute Application, роблю за аналогією. На кожному вузлі кластера запускаю IgniteRunnable(), приблизно так:

  @Override
  public void run() {
    SalesPoint sp=salesPointCache.get(spId);
    sp.calculateSalesPointCount();
    ..
  }

Додаю логіку агрегації та розвантаження, запускаю на тестовому наборі даних. Локально на сервері розробки все працює.

Запускаю два тестові сервери CentOs, вказую ip-адреси в default-config.xml, виконую на кожному

./bin/ignite.sh config/default-config.xml

Обидва вузли Ignite запускаються та бачать один одного. Вказую потрібні адреси в xml-конфізі клієнтської програми, він запускається, додає третій вузол у топологію і відразу вузлів стає знову два. У лозі значиться "ClassNotFoundException: model.SalesPoint" у рядку

SalesPoint sp=salesPointCache.get(spId);

StackOverflow каже, що причина помилки - на серверах CentOs немає класу користувача SalesPoint. Приїхали. Як же «ти не маєш manual manual deploy your Java code on each node» і далі за текстом? Чи "your Java code" - це не про SalesPoint?

Мабуть, я щось упустив — знову починаю шукати, читати і знову шукати. Через якийсь час виникає відчуття, що я прочитав по темі все, нічого нового вже немає. Поки шукав, знайшов кілька цікавих зауважень.

Valentin Куліченко, Lead Architect на GridGain Systems, відповідь на StackOverflow, квітень 2016:

Model classes are not peer deployed, but you can use withKeepBinary() flag
on the cache and query BinaryObjects. This way you will avoid deserialization
on the server side and will not get ClassNotFoundException.

Ще одна авторитетна думка: Denis Magda, Director of product management, GridGain Systems.

Стаття на Хабре про мікросервіси посилається три статті Denis Magda: Microservices Part I, Microservices Part II, Microservices Part III 2016-2017 років. У другій статті Denis пропонує стартувати вузол кластера через MaintenanceServiceNodeStartup.jar. Можна також використовувати запуск з xml-конфігурацією і командним рядком, але тоді потрібно вручну покласти користувацькі класи на кожен вузол кластера, що розгортається:

That's it. Start (..)  node using MaintenanceServiceNodeStartup file or pass
maintenance-service-node-config.xml to Apache Ignite's ignite.sh/bat scripts.
If you prefer the latter then make sure to build a jar file that will contain
all the classes from java/app/common and java/services/maintenance directories.
The jar has to be added to the classpath of every node where the service
might be deployed.

Справді, що це. Ось він, виявляється, навіщо цей загадковий бінарний формат!

3. SingleJar

Denis посів у моєму особистому рейтингу перше місце, імхо найкорисніший туторіал з усіх доступних. В його MicroServicesExample на гітхабі міститься повністю готовий приклад налаштування вузлів кластера, який компілюється без додаткових присідань.

Роблю за образом і подобою, отримую єдиний файл jar, який запускає «data node» чи «client node» залежно аргументу командного рядка. Складання запускається і працює. Zero Deployment переможений.

Перехід від мегабайтів тестових даних до десятків гігабайтів бойових показав, що бінарний формат існує недаремно. Потрібно оптимізувати витрати пам'яті на нодах, і ось тут BinaryObject виявився дуже корисним.

4. висновки

Перший закид у незрозумілості документації проекту Apache Ignite виявився справедливим, з 2016 року змінилося небагато. Новачку непросто зібрати функціонуючий прототип на основі сайту та/або репозиторію.

За підсумками виконаної роботи склалося враження, що Zero Deployment працює, але лише на системному рівні. Приблизно так: BinaryObject застосовується, щоб навчити віддалені вузли кластера працювати з класами користувача; Zero Deployment – ​​внутрішній механізм
самого Apache Ignite і розповсюджує за кластером системні об'єкти.

Сподіваюся, мій досвід буде корисним для нових користувачів Apache Ignite.

Джерело: habr.com

Додати коментар або відгук