Забезпечення високої доступності Node-RED

ДОВІДНИК З NODE-RED українською мовою

Забезпечення високої доступності Node-RED

Це перекладена стаття Bringing High Availability to Node-RED від Nick O’Leary з моїми певними приписками.

Багато компаній прагнуть розгорнути Node-RED у випадках використання, які вимагають високого ступеня доступності, надійності та масштабованості програми. Дотримуючись нашої попередньої публікації на цю тему, у цій публікації я збираюся розглянути деякі технічні деталі досягнення високої доступності, доступні підходи та те, що це означає для роботи, яку ми виконуємо у FlowForge і в Node-RED.

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

Щоб визначити, який підхід є найбільш прийнятним у контексті Node-RED, нам потрібно розглянути переваги та ускладнення кожного підходу. Це зводиться до двох факторів: залежність від стану і спосіб маршрутизації робочих потоків.

Залежність від стану (Statefulness)

Є два типи стану, які слід враховувати, коли ви думаєте про потік Node-RED: явний і неявний стан.

Явний стан — це той стан який керується застосунком. Наприклад, потік Node-RED може зберігати стан у контекстах (потоку, глобальний, вузлу) або використовувати службу зовнішньої бази даних. У FlowForge ми надаємо два типи контексту – сховище контексту в пам’яті (за замовчуванням) і постійне сховище в базі даних. Наразі сховище з базою даних містить рівень кешування пам’яті для забезпечення кращої продуктивності та взаємодії. Це ускладнює реалізацію, коли ви хочете мати кілька екземплярів, які спільно використовують одне і те ж сховище. API контексту не надає способу атомарного оновлення значень, тому ви можете зіткнутися з класичними проблемами паралельності, коли дві програми намагаються оновити одне й те саме значення.

Інший тип стану — це стан, який неявно підтримується в потоці, навіть якщо користувач явно його не налаштував. Наприклад, вузол Smooth можна використовувати для обчислення поточного середнього значення повідомлень, що проходять через нього. Вузол робить це, шляхом збереження в пам’яті останніх значень, щоб він міг перераховувати середнє з кожним оновленням. Якщо у вас є кілька екземплярів, то вузол обчислюватиме середнє значення лише для повідомлення, яке бачать його екземпляри.

Іншим прикладом неявного стану є вузол Batch, який можна використовувати для групування кількох повідомлень у єдине повідомлення-пакет. Знову ж таки, він зможе зробити це лише для групування повідомлень, які отримує той самий екземпляр.

Як обробляти стан, дуже залежить від вимог потоку та того, які вузли він використовує.

У підході з гарячим резервуванням, оскільки в будь-який час активний лише один екземпляр, багато явних обробок стану працюватимуть належним чином. Однак неявний стан залишається прив’язаним до окремих екземплярів Node-RED.

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

Ключовим висновком із цього є те, що потік потрібно створювати з урахуванням високої доступності та/або масштабування.

Робота з маршрутизації

Node-RED полегшує інтеграцію з багатьма різними джерелами подій. Парою найпоширеніших є HTTP і MQTT. Розглядаючи, як обробляти їх в кількох екземплярах застосунку, нам потрібно подумати про те, як їх завдання для їх оброблення направляється до цих екземплярів.

HTTP (сервер) є найбільш зрозумілим: перед екземплярами Node-RED ви розміщуєте проксі-сервер балансування навантаження між ними, і той подбає про спільний доступ до вхідних запитів. У сценарії гарячого резервування проксі-серверу потрібно знати, який екземпляр наразі активний – це вимагає певної координації всередині платформи для належного відстеження.

У той же час з Node-RED часто використовується MQTT. На відміну від HTTP (сервер), який є вхідним, MQTT (клієнт) працює таким чином, що Node-RED створює вихідне з’єднання з брокером, а потім підписується на потрібні теми. У перший версіях MQTT це означало, що кожен екземпляр підписувався на той самий набір тем і отримував кожне повідомлення. Це насправді не підходить до жодної з розглянутих моделей високої доступності.

З випуском MQTTv5 було додано концепцію спільних підписок: можливість для групи клієнтів підключитися, підписатися на ту саму тему та попросити брокера поширювати повідомлення між цими клієнтами. На цьому етапі ви отримуєте балансування навантаження на своїх екземплярах Node-RED, якщо вузли MQTT налаштовані належним чином.

Є багато інших вузлів, які можна використовувати для ініціювання потоків, будь то прослуховування подій в API, підключення до локально підключеного обладнання та багато іншого. Як правило, ті, які більше орієнтовані на хмару, такі як системи обміну повідомленнями, такі як Kafka та AMQP, матимуть добре налагоджені способи балансування навантаження.

У сценарії гарячого резервування керування вихідними з’єднаннями ускладнюється. Якби нам доводилося мати справу лише з вхідними з’єднаннями, екземпляр гарячого резерву міг би просто сидіти, чекаючи, поки робота буде передана йому. Але як тільки у вас є вихідні з’єднання, у вас виникає проблема. Екземпляр що виконує роль гарячого резерву має створювати вихідні з’єднання лише тоді, коли він переходить в роль активного. У реальних термінах це означає, що потоки Node-RED слід запускати лише тоді, коли екземпляр стає активним.

З нашою метою мінімізувати середній час відновлення (MTTR), нам потрібно знайти спосіб запустити цей резервний екземпляр якомога швидше; якщо для запуску резервного екземпляра потрібно стільки ж часу, скільки й для перезапуску невдалого основного екземпляра, це не є значним покращенням.

Ключовим тут є те, що Node-RED дозволяє запускати середовище виконання без запуску потоків. Це завантажує все й завчасно готує середовище виконання. Потім він може миттєво запустити потоки за допомогою простого виклику API адміністратора виконання.

Виявлення помилки

Ключовою вимогою при підході з гарячим резервуванням є знання того, коли перемикатися на резервний екзмепляр. Це вимагає ретельного моніторингу активного екземпляра, щоб дізнатися, чи він все ще працює. Те, наскільки швидко ви можете виявити збій, є ключем до скорочення часу відновлення. Саме тут вам потрібно подумати про різні способи виявлення того, як саме екземпляр перейшов в недієздатний стае: зламався (crash) - зупинився із за помилки в коді, завис (hang) - не зупинився але не виконує надалі код, чи застряг (stuck) - не реагує на зовнішні події із-за обробки інших завдань.

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

Редагування потоків

В архітектурі Node-RED кожен екземпляр також має власний редактор. Це те, що ви отримуєте, коли заходите до нього зі свого веб-браузеру.

У світі високої доступності HA, коли у вас є кілька екземплярів, що працюють за балансувальником навантаження HTTP, виникає складне питання щодо того, як редагувати потоки. Якщо кожен запит потрапляє на інший екземпляр, тоді просте завантаження редактора призведе до завантаження різних кусків із різних екземплярів. Зазвичай на рівні балансувальника навантаження це можна вирішити шляхом створення закріплених сеансів, гарантуючи таким чином, що для даного клієнта кожен запит направляється до узгодженого екземпляра. Це частково вирішує проблему, але наступне завдання полягає у вирішенні завдання, що робити, коли натиснуто кнопку “Розгорнути”. Це приведе до передачі нових потоків у напрямку від редактора до середовища виконання. Якщо у вас є кілька екземплярів, ми повинні переконатися, що всі вони при цьому оновлюються. Це досить складне завдання, яке потрібно вирішити за допомогою плинних API Node-RED, і над його вирішенням ми працюватимемо як у FlowForge, так і в попередньому проекті Node-RED.

Тим не менш, більш швидким рішенням цілком може бути використання переваг окремих екземплярів розроблення/вироблення. Ви розробляєте застосунок в одному екземплярі, і, коли ви задоволені тим, що маєте, розгортаєте його на робочому екземплярі, готовому до високої доступності. Це взагалі усуває необхідність редагувати потоки в середовищі високої доступності.

Який би метод не використовувався, виникає питання щодо того, як мінімізувати час простою під час розгортання оновлення. У чисто внутрішньому середовищі можна створювати рішення, у яких нова програма розгортається разом із старою версією, а коли все буде готово, вхідні події перенаправляються до нової версії. Але це неможливо, якщо у вас також є вихідні зв’язки. Для деяких користувачів наявність запланованого періоду обслуговування для виконання оновлень буде цілком прийнятним.

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

Продовження подорожі до HA у FlowForge

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

Ми створюємо FlowForge як відкриту платформу з можливістю працювати поверх Docker Compose та Kubernetes. Коли ми розберемося з деякими з цих функцій високої доступності, нам потрібно буде уважно поглянути на те, де ми можемо спертися на ці базові технології - ми не хочемо тут винаходити колесо.

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

Ми визначили наш початковий набір завдань і зміни в тому, як ми запускатимемо екземпляр Node-RED із середовищем k8s (Kubernetes). Ви можете стежити за нашим розвитком питання у цьому issue у нашому журналі.

Сподіваюся, ця публікація дала корисне розуміння проблем, які ми прагнемо вирішити у FlowForge. Оскільки це дуже важлива вимога для багатьох користувачів, ми інформуватимемо вас у міру прогресу.