Архітектура, заснована на подіях, з Node.js

pic

Архітектура, заснована на подіях (Event-driven architecture, EDA), є популярним шаблоном проєктування для створення високошвидкісних і масштабованих систем. Node.js з його моделлю неблокуючого вводу/виводу ідеально підходить для створення таких систем, заснованих на подіях. У цій статті ми розглянемо, як використати можливості Node.js для реалізації EDA, ефективно використовувати вбудований клас EventEmitter і створювати власні системи подій для реальних застосувань.

Чому архітектура, заснована на подіях?

EDA обертається навколо концепції подій — дій або змін стану — які захоплюються та обробляються асинхронно. Такий підхід дає кілька переваг:

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

Node.js із його неблокуючим вводу/виводу і циклом подій природно відповідає принципам EDA.

Неблокуючий ввід/вивід Node.js

Node.js працює на однопотоковому циклі подій. Замість того, щоб блокувати потік для операцій вводу/виводу (наприклад, для читання файлу або запиту до бази даних), Node.js делегує ці завдання на підсистему і продовжує обробляти інші події. Ця модель робить Node.js надзвичайно ефективним для застосувань, що потребують великих ресурсів вводу/виводу, таких як API, чат-застосунки та сервіси стрімінгу.

Роль подій в Node.js

Основна функціональність Node.js побудована навколо подій. Наприклад:

  • HTTP-сервери генерують події як request та close.
  • Потоки генерують події як data та end.
  • Об'єкт process генерує події як exit та uncaughtException.

Використання EventEmitter ефективно

Node.js надає клас EventEmitter в модулі events для обробки подієвого програмування. Давайте розглянемо, як ним користуватись.

Базове використання EventEmitter

const EventEmitter = require('events');  

class MyEmitter extends EventEmitter {}  
const myEmitter = new MyEmitter();  
// Реєструємо прослуховувач події  
myEmitter.on('greet', (name) => {  
 console.log(`Привіт, ${name}!`);  
});  
// Генеруємо подію  
myEmitter.emit('greet', 'Priyanshu');

Ключові методи в EventEmitter

  • on(event, listener): Реєструє прослуховувач (Event Listener) для вказаної події.
  • emit(event, ...args): Генерує подію, викликаючи всі зареєстровані прослуховувачі (Event Listener).
  • once(event, listener): Реєструє одноразовий прослуховувач (Event Listener) для події.
  • removeListener(event, listener): Видаляє конкретний прослуховувач (Event Listener).

Обробка помилок з EventEmitter

Якщо подія error згенерована, а прослуховувачі (Event Listener) не зареєстровані, Node.js викидає виключення. Завжди обробляйте помилки:

myEmitter.on('error', (err) => {  
 console.error('Сталася помилка:', err.message);  
});  

myEmitter.emit('error', new Error('Щось пішло не так!'));

Реалізація власних систем подій

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

Приклад: Простора система Pub/Sub

Система публікації/підписки (Pub/Sub) — це популярний шаблон в EDA.
Ось як ви можете реалізувати це:

class PubSub {  
 constructor() {  
 this.events = {};  
 }  

subscribe(event, listener) {  
 if (!this.events[event]) {  
 this.events[event] = [];  
 }  
 this.events[event].push(listener);  
 }  
 publish(event, data) {  
 if (this.events[event]) {  
 this.events[event].forEach((listener) => listener(data));  
 }  
 }  
 unsubscribe(event, listener) {  
 if (this.events[event]) {  
 this.events[event] = this.events[event].filter((l) => l !== listener);  
 }  
 }  
}  
// Використання  
const pubsub = new PubSub();  
const onOrderPlaced = (order) => console.log(`Замовлення отримано: ${order.id}`);  
pubsub.subscribe('orderPlaced', onOrderPlaced);  
pubsub.publish('orderPlaced', { id: 123, item: 'Ноутбук' });  
pubsub.unsubscribe('orderPlaced', onOrderPlaced);

Приклад: Мікросервіси, засновані на подіях

В розподіленій системі ви можете використовувати брокери повідомлень, такі як RabbitMQ, Kafka або Redis, для реалізації подієвого зв'язку між мікросервісами. Бібліотеки Node.js, як amqplib або kafkajs, спрощують інтеграцію.

Приклад RabbitMQ

const amqp = require('amqplib');  

(async () => {  
 const connection = await amqp.connect('amqp://localhost');  
 const channel = await connection.createChannel();  
 const queue = 'tasks';  
 await channel.assertQueue(queue);  
 // Продюсер  
 channel.sendToQueue(queue, Buffer.from(JSON.stringify({ task: 'Обробка замовлення' })));  
 console.log('Повідомлення відправлено');  
 // Споживач  
 channel.consume(queue, (message) => {  
 console.log('Отримано:', message.content.toString());  
 channel.ack(message);  
 });  
})();

Кращі практики для систем, заснованих на подіях

  1. Уникайте надмірного використання подій: Надмірне використання подій може призвести до непередбачуваних результатів і важких для налагодження систем.
  2. Документуйте події: Підтримуйте чітку документацію для подій, включаючи структуру їх корисного навантаження.
  3. Моніторинг потоку подій: Використовуйте інструменти для ведення журналів або моніторингу, щоб відстежувати потік подій.
  4. Обробка помилок: Завжди обробляйте помилки належним чином, щоб уникнути збоїв системи.
  5. Тестування: Тестуйте системи, засновані на подіях, ретельно, особливо для крайніх випадків і умов гонки.

Висновок

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

Почніть впроваджувати EDA у свої проєкти на Node.js вже сьогодні, щоб на власному досвіді переконатися в усіх перевагах. Є питання або свої приклади? Поділіться ними в коментарях нижче!

Перекладено з: Event-Driven Architecture with Node.js

Leave a Reply

Your email address will not be published. Required fields are marked *