Створення мікросервісів з RabbitMQ за допомогою NestJS

Мікросервісна архітектура — це сучасний підхід до створення масштабованих та декуплованих додатків. У цьому блозі я поділюсь, як я побудував систему мікросервісів, використовуючи NestJS для бекенду, RabbitMQ для обміну повідомленнями та Next.js для інтерфейсу користувача, щоб візуалізувати роботу системи в реальному часі.

Огляд архітектури

Цей проект складається з двох мікросервісів:

  1. Адміністративний мікросервіс: відповідає за управління продуктами, зберігає дані про продукти в PostgreSQL і синхронно відправляє повідомлення в RabbitMQ.
  2. Основний мікросервіс: слухає повідомлення RabbitMQ і синхронізує дані в MongoDB.

Ключові особливості:

  • Управління продуктами: Адміністратор може додавати нові продукти через адміністративний мікросервіс, які синхронізуються в реальному часі з основним мікросервісом.
  • Взаємодія з користувачем: Дії користувачів, такі як вподобання продуктів, обробляються основним мікросервісом і відправляються назад в RabbitMQ для подальшої синхронізації.
  • Візуалізація в реальному часі: Фронтенд на Next.js візуалізує весь процес, як показано у демонстраційному відео.

Теорія про RabbitMQ та комунікацію між мікросервісами

RabbitMQ — це брокер повідомлень, який дозволяє мікросервісам спілкуватися асинхронно. Ця архітектура забезпечує слабке зв'язування, високу масштабованість і відмовостійкість. Ось як це працює в цьому проекті:

  1. Виробник: Адміністративний мікросервіс публікує повідомлення (наприклад, деталі нового продукту) в RabbitMQ.
  2. Черга повідомлень: RabbitMQ зберігає ці повідомлення в черзі, поки вони не будуть спожиті.
  3. Споживач: Основний мікросервіс слухає чергу RabbitMQ, обробляє повідомлення і оновлює MongoDB.

Цей підхід забезпечує узгодженість даних і синхронізацію в реальному часі між сервісами.

Технічний стек

  • Фреймворк для бекенду: NestJS
  • Фреймворк для фронтенду: Next.js
  • Брокер повідомлень: RabbitMQ
  • Бази даних: PostgreSQL (для адміністративного мікросервісу) і MongoDB (для основного мікросервісу)

Реалізація

Передумови: Для цього доказу концепції (POC) я створив службу RabbitMQ за допомогою CloudAMQP.
Я створив інстанс з планом Little Lemur (безкоштовно), який надає службу RabbitMQ. Після створення інстанса, скопіюйте AMQP URL, що надається в деталях інстанса.
Цей URL буде використовуватися для підключення до RabbitMQ.

pic

1. Налаштування RabbitMQ в NestJS

Встановіть необхідну бібліотеку RabbitMQ:

npm install @nestjs/microservices

Налаштуйте RabbitMQ в обох мікросервісах:

Адміністративний мікросервіс (product.module.ts):

import { Injectable } from '@nestjs/common';  
import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices';
import { Module } from '@nestjs/common';  
import { ClientsModule, Transport } from '@nestjs/microservices';  
import { TypeOrmModule } from '@nestjs/typeorm';  
import { Product } from './entity/product.entity';  
import { ProductController } from './product.controller';  
import { ProductService } from './product.service';  

@Module({  
 imports: [  
 TypeOrmModule.forFeature([Product]),  
 ClientsModule.register([  
 {  
 name: 'PRODUCT_SERVICE',  
 transport: Transport.RMQ,  
 options: {  
 urls: [  

 ],  
 queue: 'main_queue',  
 queueOptions: {  
 durable: false,  
 },  
 },  
 },  
 ]),  
 ],  

 providers: [ProductService],  
 controllers: [ProductController],  
 exports: [ProductService],  
})  
export class ProductModule {}

Адміністративний мікросервіс (product.controller.ts)

Приклад надсилання пакета даних до основного мікросервісу через RabbitMQ:

Post()  
 async createProduct(@Body() body: { title: string; image: string }) {  
 const product = await this.productService.createProduct(body);  
 this.client.emit('product_created', product);  
 return product;  
 }  

 @Patch(':id')  
 async updateProduct(  
 @Param('id') id: number,  
 @Body() body: { title?: string; image?: string },  
 ) {  
 const updateResult = await this.productService.updateProduct(id, body);  
 const product = await this.productService.getProduct(id);  

 if (updateResult) {  
 this.client.emit('product_updated', product);  
 return {  
 status: 200,  
 message: 'Product updated successfully',  
 };  
 } else {  
 return {  
 status: 400,  
 message: 'Product not updated',  
 };  
 }  
 }  
}

Інтеграція RabbitMQ в основний мікросервіс:

import { NestFactory } from '@nestjs/core';  
import { AppModule } from './app.module';  
import { MicroserviceOptions, Transport } from '@nestjs/microservices';  

async function bootstrap() {  

 const app = await NestFactory.createMicroservice(  
 AppModule,  
 {  
 transport: Transport.RMQ,  
 options: {  
 urls: [  

 ],  
 queue: 'main_queue',  
 queueOptions: {  
 durable: false,  
 },  
 },  
 },  
 );  

 await app.listen();  
 console.log('Microservice is listening using RabbitMQ');  
}  
bootstrap();

Основний мікросервіс (main.service.ts):

import { Injectable } from '@nestjs/common';  
import { EventPattern } from '@nestjs/microservices';
@EventPattern('product_created')  
 async create(data: Product) {  
 return this.productService.create({  
 id: data.id,  
 title: data.title,  
 image: data.image,  
 likes: data.likes,  
 });  
 }  

 @EventPattern('product_updated')  
 @EventPattern('product_liked')  
 async update(product: Product) {  
 return this.productService.update(product.id, product);  
 }

2. Синхронізація дій користувачів (наприклад, вподобання)

Розширте той самий підхід для синхронізації взаємодії користувача через RabbitMQ:

Основний мікросервіс:

@EventPattern('product_liked')  
async handleProductLiked(payload: { productId: string, userId: string }) {  
 // Обробка вподобання продукту та оновлення MongoDB  
}

Адміністративний мікросервіс (публікація вподобань):

async userLikedProduct(payload: { productId: string, userId: string }) {  
 this.client.emit('product_liked', payload);  
}

Візуалізація з Next.js

Фронтенд на Next.js надає зручний інтерфейс для взаємодії з мікросервісами.
Наприклад, список продуктів і взаємодії з користувачами можуть відображатися в реальному часі, отримуючи дані від Основного Мікросервісу.

Приклад API виклику на Next.js:

const Add = () => {  
 const [title,setTitle]=useState("");  
 const [image,setImage]=useState("");  

const handleAdd=async(title,image)=>{  
 console.log('title',title);  
 console.log('image',image);  
const myHeaders = new Headers();  
myHeaders.append("Content-Type", "application/json");  

const raw = JSON.stringify({  
 "title": title,  
 "image": image  
});  

const requestOptions = {  
 method: "POST",  
 headers: myHeaders,  
 body: raw,  
 redirect: "follow"  
};  

const result=await fetch("http://localhost:8000/v1/api/products", requestOptions);  
console.log('result',result)  
if(result.status===201){  
 toast.success("Successfully added")  
 setTitle("");  
 setImage("");  
 }else{  
 toast.error("Failed to add")  
 }  
}

Демонстраційне відео та код

Ось коротке відео, що демонструє роботу системи:
🎥 Подивитися демонстрацію

Повний вихідний код можна знайти тут:
🔗 Завантаження незабаром…

Переваги цього підходу

  1. Розділена архітектура: Кожен мікросервіс працює незалежно, що робить систему модульною та легшою в обслуговуванні.
  2. Комунікація в реальному часі: RabbitMQ забезпечує синхронізацію даних у реальному часі.
  3. Масштабованість: Обидва мікросервіси можна масштабувати незалежно для обробки зростаючого навантаження.

Висновок

Цей проект демонструє, як побудувати масштабовану, розділену архітектуру мікросервісів за допомогою RabbitMQ, NestJS та Next.js. RabbitMQ є основою для комунікації, забезпечуючи синхронізацію в реальному часі між сервісами. Система не лише надійна, але й розширювана для майбутніх потреб.

Перекладено з: Building Microservices with RabbitMQ Using NestJS

Leave a Reply

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