Что такое microservices transport (TCP, Redis, Kafka) в NestJS?
Транспортный слой в NestJS microservices
NestJS не является брокером сообщений сам по себе — он предоставляет унифицированную абстракцию поверх разных транспортов. При создании микросервиса через NestFactory.createMicroservice() вы указываете Transport — стратегию, которая определяет протокол доставки сообщений. Приложение работает с одинаковыми декораторами @MessagePattern и @EventPattern независимо от того, какой транспорт выбран.
TCP
Встроенный транспорт по умолчанию, ничего дополнительно ставить не нужно. Работает по схеме точка-точка: клиент открывает сокет к конкретному хосту/порту сервиса. Подходит для простых внутренних RPC-вызовов, но не даёт балансировки из коробки и требует service discovery на уровне инфраструктуры (например, Kubernetes Service).
Redis
Использует pub/sub Redis как шину сообщений. Требует пакет ioredis. Хорошо подходит для fire-and-forget событий и лёгких нагрузок, но pub/sub Redis не гарантирует доставку — если подписчик офлайн, сообщение теряется, персистентности очереди нет (в отличие от Redis Streams, которые NestJS напрямую как транспорт не использует).
Kafka
Использует kafkajs под капотом. Kafka — это распределённый лог событий с партициями, consumer group'ами и гарантией порядка внутри партиции. Подходит для event-driven архитектур, где важны durability, replay событий и горизонтальное масштабирование consumer'ов. Требует настройки client (brokers) и consumer (groupId).
Паттерны обмена сообщениями
@MessagePattern— request-response: клиент ждёт ответ (client.send()), под капотом это Observable.@EventPattern— fire-and-forget события (client.emit()), ответа не ожидается, используется для событийной интеграции.
ClientProxy
Отправка сообщений из другого сервиса или из HTTP-контроллера идёт через ClientProxy, который регистрируется через ClientsModule.register() с тем же transport-объектом, что и на стороне получателя.
Гибридные приложения
Через app.connectMicroservice() можно поднять и HTTP, и один или несколько микросервисных транспортов в одном процессе — это удобно, когда сервис одновременно принимает REST-запросы и слушает события Kafka.
Кастомная сериализация
Для каждого транспорта можно задать свои serializer/deserializer в опциях стратегии — это важно для Kafka, где часто нужен Avro/Protobuf вместо JSON по умолчанию.
Ключевое отличие для собеседования
TCP — простой синхронный RPC без гарантий доставки при сбоях сети. Redis pub/sub — быстрый, но без персистентности и at-least-once доставки. Kafka — надёжный event log с партиционированием, consumer group'ами, возможностью replay и масштабирования, но с более высокой операционной сложностью и задержкой по сравнению с TCP.
Что хочет услышать интервьюер
Понимание, что transport — это стратегия (Transport enum), а не сам брокер, и NestJS абстрагирует протокол через единый API
Чёткое разграничение @MessagePattern (request-response) и @EventPattern (fire-and-forget)
Знание отличий гарантий доставки: TCP — point-to-point без retry, Redis pub/sub — at-most-once, Kafka — durable log с consumer group и replay
Понимание роли ClientProxy и того, что конфигурация транспорта должна совпадать у отправителя и получателя
Осведомлённость про гибридные приложения (HTTP + микросервисный транспорт в одном процессе)
Пример: Микросервис на TCP
// main.ts
import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: { host: '0.0.0.0', port: 3001 },
},
);
await app.listen();
}
bootstrap();
Пример: Микросервис на Kafka с consumer group
// main.ts
import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.KAFKA,
options: {
client: { brokers: ['localhost:9092'] },
consumer: { groupId: 'orders-consumer' },
},
},
);
await app.listen();
}
bootstrap();
Пример: Обработчики сообщений и событий
import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern, Payload } from '@nestjs/microservices';
@Controller()
export class OrdersController {
// request-response: клиент ждёт результат
@MessagePattern('orders.get')
getOrder(@Payload() id: string) {
return { id, status: 'shipped' };
}
// fire-and-forget: ответ не отправляется
@EventPattern('orders.created')
handleOrderCreated(@Payload() data: { orderId: string }) {
// например, отправка уведомления
console.log('Новый заказ создан:', data.orderId);
}
}
Пример: Клиент через ClientsModule
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';
@Module({
imports: [
ClientsModule.register([
{
name: 'ORDERS_SERVICE',
transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 },
},
]),
],
})
export class AppModule {}
Типичные ошибки
Путают @MessagePattern и @EventPattern, считая что оба всегда ждут ответ
Не знают, что Redis pub/sub в NestJS не гарантирует доставку сообщений при недоступности подписчика
Считают Kafka взаимозаменяемым с очередью типа RabbitMQ, не упоминая партиции и consumer group как ключевые отличия
Забывают, что клиент и сервер должны использовать идентичную конфигурацию транспорта (host/port, brokers, groupId)
Не упоминают, что TCP-транспорт не даёт балансировки нагрузки и service discovery из коробки


