Мікросервісна архітектура — це сучасний підхід до створення масштабованих та декуплованих додатків. У цьому блозі я поділюсь, як я побудував систему мікросервісів, використовуючи NestJS для бекенду, RabbitMQ для обміну повідомленнями та Next.js для інтерфейсу користувача, щоб візуалізувати роботу системи в реальному часі.
Огляд архітектури
Цей проект складається з двох мікросервісів:
- Адміністративний мікросервіс: відповідає за управління продуктами, зберігає дані про продукти в PostgreSQL і синхронно відправляє повідомлення в RabbitMQ.
- Основний мікросервіс: слухає повідомлення RabbitMQ і синхронізує дані в MongoDB.
Ключові особливості:
- Управління продуктами: Адміністратор може додавати нові продукти через адміністративний мікросервіс, які синхронізуються в реальному часі з основним мікросервісом.
- Взаємодія з користувачем: Дії користувачів, такі як вподобання продуктів, обробляються основним мікросервісом і відправляються назад в RabbitMQ для подальшої синхронізації.
- Візуалізація в реальному часі: Фронтенд на Next.js візуалізує весь процес, як показано у демонстраційному відео.
Теорія про RabbitMQ та комунікацію між мікросервісами
RabbitMQ — це брокер повідомлень, який дозволяє мікросервісам спілкуватися асинхронно. Ця архітектура забезпечує слабке зв'язування, високу масштабованість і відмовостійкість. Ось як це працює в цьому проекті:
- Виробник: Адміністративний мікросервіс публікує повідомлення (наприклад, деталі нового продукту) в RabbitMQ.
- Черга повідомлень: RabbitMQ зберігає ці повідомлення в черзі, поки вони не будуть спожиті.
- Споживач: Основний мікросервіс слухає чергу RabbitMQ, обробляє повідомлення і оновлює MongoDB.
Цей підхід забезпечує узгодженість даних і синхронізацію в реальному часі між сервісами.
Технічний стек
- Фреймворк для бекенду: NestJS
- Фреймворк для фронтенду: Next.js
- Брокер повідомлень: RabbitMQ
- Бази даних: PostgreSQL (для адміністративного мікросервісу) і MongoDB (для основного мікросервісу)
Реалізація
Передумови: Для цього доказу концепції (POC) я створив службу RabbitMQ за допомогою CloudAMQP.
Я створив інстанс з планом Little Lemur (безкоштовно), який надає службу RabbitMQ. Після створення інстанса, скопіюйте AMQP URL, що надається в деталях інстанса.
Цей URL буде використовуватися для підключення до RabbitMQ.
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")
}
}
Демонстраційне відео та код
Ось коротке відео, що демонструє роботу системи:
🎥 Подивитися демонстрацію
Повний вихідний код можна знайти тут:
🔗 Завантаження незабаром…
Переваги цього підходу
- Розділена архітектура: Кожен мікросервіс працює незалежно, що робить систему модульною та легшою в обслуговуванні.
- Комунікація в реальному часі: RabbitMQ забезпечує синхронізацію даних у реальному часі.
- Масштабованість: Обидва мікросервіси можна масштабувати незалежно для обробки зростаючого навантаження.
Висновок
Цей проект демонструє, як побудувати масштабовану, розділену архітектуру мікросервісів за допомогою RabbitMQ, NestJS та Next.js. RabbitMQ є основою для комунікації, забезпечуючи синхронізацію в реальному часі між сервісами. Система не лише надійна, але й розширювана для майбутніх потреб.
Перекладено з: Building Microservices with RabbitMQ Using NestJS