Sam Baek, The Dev's Corner

๐Ÿ“ฌ ๋ฉ”์‹œ์ง€ ํ ์™„๋ฒฝ ๊ฐ€์ด๋“œ (RabbitMQ, Kafka, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ)

13 Nov 2025

๋ฉ”์‹œ์ง€ ํ๋ž€ ๋ฌด์—‡์ธ๊ฐ€


ํŽธ์˜์  ํƒ๋ฐฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.
๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์ด ํƒ๋ฐฐ๋ฅผ ๋งก๊ธฐ๋ฉด,
๋ฐ›๋Š” ์‚ฌ๋žŒ์ด ๋‚˜์ค‘์— ์ฐพ์•„๊ฐ„๋‹ค.

๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์€ ๋ฐ›๋Š” ์‚ฌ๋žŒ์„ ๊ธฐ๋‹ค๋ฆด ํ•„์š” ์—†๋‹ค.
๋ฐ›๋Š” ์‚ฌ๋žŒ๋„ ๋ณด๋‚ด๋Š” ์‚ฌ๋žŒ์„ ๊ธฐ๋‹ค๋ฆด ํ•„์š” ์—†๋‹ค.

๋ฉ”์‹œ์ง€ ํ๋Š” ์ด๋Ÿฐ ํƒ๋ฐฐ ๋ณด๊ด€ํ•จ ์—ญํ• ์„ ํ•œ๋‹ค.
์‹œ์Šคํ…œ ๊ฐ„ ๋ฉ”์‹œ์ง€๋ฅผ ์ž„์‹œ ์ €์žฅํ•˜๊ณ ,
๋ฐ›๋Š” ์ชฝ์ด ์ค€๋น„๋˜๋ฉด ์ฒ˜๋ฆฌํ•œ๋‹ค.

์™œ ๋ฉ”์‹œ์ง€ ํ๋ฅผ ๋ฐฐ์›Œ์•ผ ํ• ๊นŒ?


์ด์œ  1: ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ
์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…์„ ๋‚˜์ค‘์— ์ฒ˜๋ฆฌ

์ด์œ  2: ์‹œ์Šคํ…œ ๋ถ„๋ฆฌ
์„œ๋น„์Šค ๊ฐ„ ๋А์Šจํ•œ ๊ฒฐํ•ฉ

์ด์œ  3: ๋ถ€ํ•˜ ๋ถ„์‚ฐ
ํŠธ๋ž˜ํ”ฝ ๊ธ‰์ฆ ์‹œ ๋ฒ„ํผ ์—ญํ• 

์ด์œ  4: ๋ฉด์ ‘ ํ•„์ˆ˜
MSA, ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜ ๋‹จ๊ณจ ์งˆ๋ฌธ

๊ธฐ๋ณธ ๊ฐœ๋… ์š”์•ฝ


๐Ÿท๏ธ ๋ฉ”์‹œ์ง€ ํ ๊ตฌ์กฐ


[Producer]  โ”€โ”€โ†’  [Message Queue]  โ”€โ”€โ†’  [Consumer]
 (๋ฐœ์‹ ์ž)          (๋ฉ”์‹œ์ง€ ์ €์žฅ์†Œ)        (์ˆ˜์‹ ์ž)


Producer (์ƒ์‚ฐ์ž)


๊ฐœ๋…: ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ์ชฝ

์˜ˆ์‹œ:

  • ์ฃผ๋ฌธ ์„œ๋น„์Šค๊ฐ€ โ€œ์ฃผ๋ฌธ ์ƒ์„ฑ๋จโ€ ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰
  • ๊ฒฐ์ œ ์„œ๋น„์Šค๊ฐ€ โ€œ๊ฒฐ์ œ ์™„๋ฃŒโ€ ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰


Queue (ํ)


๊ฐœ๋…: ๋ฉ”์‹œ์ง€๋ฅผ ์ž„์‹œ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„

ํŠน์ง•:

  • FIFO (First In First Out)
  • ๋ฉ”์‹œ์ง€ ์˜์†์„ฑ ๋ณด์žฅ
  • ์—ฌ๋Ÿฌ Consumer๊ฐ€ ๊ตฌ๋… ๊ฐ€๋Šฅ


Consumer (์†Œ๋น„์ž)


๊ฐœ๋…: ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ์ชฝ

์˜ˆ์‹œ:

  • ์•Œ๋ฆผ ์„œ๋น„์Šค๊ฐ€ โ€œ์ฃผ๋ฌธ ์ƒ์„ฑ๋จโ€ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ 
  • ๋ฐฐ์†ก ์„œ๋น„์Šค๊ฐ€ โ€œ๊ฒฐ์ œ ์™„๋ฃŒโ€ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ 


๐Ÿท๏ธ ๋ฉ”์‹œ์ง• ํŒจํ„ด


1. Point-to-Point (P2P)


[Producer] โ”€โ”€โ†’ [Queue] โ”€โ”€โ†’ [Consumer]
                  โ”‚
                  โ””โ”€โ”€โ†’ ํ•˜๋‚˜์˜ Consumer๋งŒ ์ฒ˜๋ฆฌ


ํŠน์ง•: ๋ฉ”์‹œ์ง€๋‹น ํ•˜๋‚˜์˜ Consumer๋งŒ ์ฒ˜๋ฆฌ
์‚ฌ์šฉ ์˜ˆ: ์ž‘์—… ๋ถ„๋ฐฐ, ํƒœ์Šคํฌ ํ

2. Publish/Subscribe (Pub/Sub)


                    โ”Œโ”€โ”€โ†’ [Consumer 1]
[Producer] โ”€โ”€โ†’ [Topic] โ”€โ”€โ†’ [Consumer 2]
                    โ””โ”€โ”€โ†’ [Consumer 3]


ํŠน์ง•: ๋ชจ๋“  ๊ตฌ๋…์ž๊ฐ€ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹ 
์‚ฌ์šฉ ์˜ˆ: ์ด๋ฒคํŠธ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ, ์•Œ๋ฆผ

๐Ÿท๏ธ RabbitMQ vs Kafka


๊ตฌ๋ถ„ RabbitMQ Kafka
๋ชจ๋ธ ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค ์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆฌ๋ฐ
๋ฉ”์‹œ์ง€ ๋ณด๊ด€ ์†Œ๋น„ ํ›„ ์‚ญ์ œ ์˜๊ตฌ ๋ณด๊ด€
์ฒ˜๋ฆฌ๋Ÿ‰ ์ค‘๊ฐ„ ๋งค์šฐ ๋†’์Œ
์ˆœ์„œ ๋ณด์žฅ ํ ๋‹จ์œ„ ํŒŒํ‹ฐ์…˜ ๋‹จ์œ„
์žฌ์ฒ˜๋ฆฌ ์–ด๋ ค์›€ ์‰ฌ์›€
์ ํ•ฉํ•œ ๊ฒฝ์šฐ ์ž‘์—… ํ, RPC ๋กœ๊ทธ, ์ด๋ฒคํŠธ ์†Œ์‹ฑ


๐Ÿท๏ธ ํ•ต์‹ฌ ์šฉ์–ด


Exchange (RabbitMQ): ๋ฉ”์‹œ์ง€ ๋ผ์šฐํŒ… ๊ทœ์น™
Topic (Kafka): ๋ฉ”์‹œ์ง€ ์นดํ…Œ๊ณ ๋ฆฌ
Partition (Kafka): ํ† ํ”ฝ ๋‚ด ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ๋‹จ์œ„
Consumer Group: ๊ฐ™์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚˜๋ˆ  ์ฒ˜๋ฆฌํ•˜๋Š” ๊ทธ๋ฃน
Offset (Kafka): ๋ฉ”์‹œ์ง€ ์œ„์น˜ (์žฌ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)
ACK: ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ์™„๋ฃŒ ํ™•์ธ

์‹ค์ „ ์˜ˆ์‹œ


๐Ÿท๏ธ RabbitMQ + NestJS


1. ์„ค์น˜ ๋ฐ ์„ค์ •


# RabbitMQ Docker ์‹คํ–‰
docker run -d --name rabbitmq \
  -p 5672:5672 -p 15672:15672 \
  rabbitmq:3-management

# NestJS ํŒจํ‚ค์ง€ ์„ค์น˜
npm install @nestjs/microservices amqplib amqp-connection-manager


2. Producer ๊ตฌํ˜„


// src/orders/orders.module.ts
import { Module } from "@nestjs/common";
import { ClientsModule, Transport } from "@nestjs/microservices";

@Module({
  imports: [
    ClientsModule.register([
      {
        name: "NOTIFICATION_SERVICE",
        transport: Transport.RMQ,
        options: {
          urls: ["amqp://localhost:5672"],
          queue: "notifications_queue",
          queueOptions: { durable: true },
        },
      },
    ]),
  ],
})
export class OrdersModule {}

// src/orders/orders.service.ts
import { Inject, Injectable } from "@nestjs/common";
import { ClientProxy } from "@nestjs/microservices";

@Injectable()
export class OrdersService {
  constructor(
    @Inject("NOTIFICATION_SERVICE")
    private readonly notificationClient: ClientProxy
  ) {}

  async createOrder(dto: CreateOrderDto): Promise<Order> {
    // 1. ์ฃผ๋ฌธ ์ƒ์„ฑ
    const order = await this.orderRepository.save({
      userId: dto.userId,
      items: dto.items,
      status: "PENDING",
    });

    // 2. ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰ (๋น„๋™๊ธฐ)
    this.notificationClient.emit("order_created", {
      orderId: order.id,
      userId: order.userId,
      totalAmount: order.totalAmount,
    });

    // 3. ์ฆ‰์‹œ ์‘๋‹ต (์•Œ๋ฆผ์€ ๋‚˜์ค‘์— ์ฒ˜๋ฆฌ๋จ)
    return order;
  }

  async cancelOrder(orderId: string): Promise<void> {
    const order = await this.orderRepository.findById(orderId);
    order.status = "CANCELLED";
    await this.orderRepository.save(order);

    // ์ทจ์†Œ ์ด๋ฒคํŠธ ๋ฐœํ–‰
    this.notificationClient.emit("order_cancelled", {
      orderId: order.id,
      userId: order.userId,
    });
  }
}


3. Consumer ๊ตฌํ˜„


// src/notifications/notifications.controller.ts
import { Controller } from "@nestjs/common";
import { EventPattern, Payload } from "@nestjs/microservices";

@Controller()
export class NotificationsController {
  constructor(
    private readonly emailService: EmailService,
    private readonly pushService: PushService
  ) {}

  @EventPattern("order_created")
  async handleOrderCreated(
    @Payload() data: { orderId: string; userId: string; totalAmount: number }
  ): Promise<void> {
    console.log("์ฃผ๋ฌธ ์ƒ์„ฑ ์ด๋ฒคํŠธ ์ˆ˜์‹ :", data);

    // ์ด๋ฉ”์ผ ๋ฐœ์†ก
    await this.emailService.sendOrderConfirmation(
      data.userId,
      data.orderId,
      data.totalAmount
    );

    // ํ‘ธ์‹œ ์•Œ๋ฆผ
    await this.pushService.sendNotification(
      data.userId,
      `์ฃผ๋ฌธ์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ฃผ๋ฌธ๋ฒˆํ˜ธ: ${data.orderId}`
    );
  }

  @EventPattern("order_cancelled")
  async handleOrderCancelled(
    @Payload() data: { orderId: string; userId: string }
  ): Promise<void> {
    console.log("์ฃผ๋ฌธ ์ทจ์†Œ ์ด๋ฒคํŠธ ์ˆ˜์‹ :", data);

    await this.emailService.sendOrderCancellation(data.userId, data.orderId);
  }
}

// main.ts (Consumer ์„œ๋น„์Šค)
import { NestFactory } from "@nestjs/core";
import { Transport, MicroserviceOptions } from "@nestjs/microservices";

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    NotificationsModule,
    {
      transport: Transport.RMQ,
      options: {
        urls: ["amqp://localhost:5672"],
        queue: "notifications_queue",
        queueOptions: { durable: true },
        noAck: false, // ์ˆ˜๋™ ACK
      },
    }
  );

  await app.listen();
  console.log("Notification ์„œ๋น„์Šค ์‹œ์ž‘");
}
bootstrap();


๐Ÿท๏ธ Kafka + NestJS


1. ์„ค์น˜ ๋ฐ ์„ค์ •


# Kafka Docker Compose
# docker-compose.yml
version: '3'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
    ports:
      - "2181:2181"

  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
# NestJS Kafka ํŒจํ‚ค์ง€
npm install @nestjs/microservices kafkajs


2. Producer ๊ตฌํ˜„


// src/orders/orders.module.ts
import { Module } from "@nestjs/common";
import { ClientsModule, Transport } from "@nestjs/microservices";

@Module({
  imports: [
    ClientsModule.register([
      {
        name: "KAFKA_SERVICE",
        transport: Transport.KAFKA,
        options: {
          client: {
            clientId: "orders",
            brokers: ["localhost:9092"],
          },
          producer: {
            allowAutoTopicCreation: true,
          },
        },
      },
    ]),
  ],
})
export class OrdersModule {}

// src/orders/orders.service.ts
@Injectable()
export class OrdersService {
  constructor(
    @Inject("KAFKA_SERVICE")
    private readonly kafkaClient: ClientKafka
  ) {}

  async onModuleInit() {
    // ํ† ํ”ฝ ๊ตฌ๋… (์‘๋‹ต ๋ฐ›์„ ๊ฒฝ์šฐ)
    this.kafkaClient.subscribeToResponseOf("order.created");
    await this.kafkaClient.connect();
  }

  async createOrder(dto: CreateOrderDto): Promise<Order> {
    const order = await this.orderRepository.save({
      userId: dto.userId,
      items: dto.items,
      status: "PENDING",
    });

    // Kafka ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰
    this.kafkaClient.emit("order.created", {
      key: order.id, // ํŒŒํ‹ฐ์…˜ ํ‚ค
      value: {
        orderId: order.id,
        userId: order.userId,
        items: order.items,
        totalAmount: order.totalAmount,
        createdAt: new Date().toISOString(),
      },
    });

    return order;
  }
}


3. Consumer ๊ตฌํ˜„


// src/inventory/inventory.controller.ts
import { Controller } from "@nestjs/common";
import { MessagePattern, Payload } from "@nestjs/microservices";

@Controller()
export class InventoryController {
  constructor(private readonly inventoryService: InventoryService) {}

  @MessagePattern("order.created")
  async handleOrderCreated(
    @Payload()
    message: {
      orderId: string;
      items: Array<{ productId: string; quantity: number }>;
    }
  ): Promise<void> {
    console.log("์žฌ๊ณ  ์ฐจ๊ฐ ์ด๋ฒคํŠธ ์ˆ˜์‹ :", message.orderId);

    // ์žฌ๊ณ  ์ฐจ๊ฐ
    for (const item of message.items) {
      await this.inventoryService.decreaseStock(item.productId, item.quantity);
    }
  }
}

// main.ts (Consumer ์„œ๋น„์Šค)
async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    InventoryModule,
    {
      transport: Transport.KAFKA,
      options: {
        client: {
          brokers: ["localhost:9092"],
          clientId: "inventory-consumer",
        },
        consumer: {
          groupId: "inventory-group",
        },
      },
    }
  );

  await app.listen();
}


๐Ÿท๏ธ ์—๋Ÿฌ ์ฒ˜๋ฆฌ์™€ ์žฌ์‹œ๋„


// Dead Letter Queue (DLQ) ํŒจํ„ด
@Injectable()
export class OrderEventHandler {
  private readonly MAX_RETRIES = 3;

  @EventPattern("order.created")
  async handleOrderCreated(@Payload() data: OrderCreatedEvent): Promise<void> {
    try {
      await this.processOrder(data);
    } catch (error) {
      // ์žฌ์‹œ๋„ ํšŸ์ˆ˜ ํ™•์ธ
      const retryCount = data.retryCount || 0;

      if (retryCount < this.MAX_RETRIES) {
        // ์žฌ์‹œ๋„
        this.kafkaClient.emit("order.created", {
          ...data,
          retryCount: retryCount + 1,
        });
      } else {
        // DLQ๋กœ ์ด๋™
        this.kafkaClient.emit("order.created.dlq", {
          ...data,
          error: error.message,
          failedAt: new Date().toISOString(),
        });
      }
    }
  }
}

// ๋ฉฑ๋“ฑ์„ฑ ๋ณด์žฅ
@Injectable()
export class IdempotentHandler {
  constructor(private readonly redis: Redis) {}

  async handleMessage(messageId: string, handler: () => Promise<void>) {
    // ์ด๋ฏธ ์ฒ˜๋ฆฌ๋œ ๋ฉ”์‹œ์ง€์ธ์ง€ ํ™•์ธ
    const processed = await this.redis.get(`processed:${messageId}`);
    if (processed) {
      console.log("์ด๋ฏธ ์ฒ˜๋ฆฌ๋œ ๋ฉ”์‹œ์ง€:", messageId);
      return;
    }

    // ์ฒ˜๋ฆฌ
    await handler();

    // ์ฒ˜๋ฆฌ ์™„๋ฃŒ ํ‘œ์‹œ (24์‹œ๊ฐ„ ์œ ์ง€)
    await this.redis.set(`processed:${messageId}`, "1", "EX", 86400);
  }
}


๐Ÿท๏ธ ์‹ค์ „ ์•„ํ‚คํ…์ฒ˜


โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   ์ฃผ๋ฌธ API   โ”‚โ”€โ”€โ”€โ”€โ†’โ”‚   Kafka     โ”‚โ”€โ”€โ”€โ”€โ†’โ”‚  ์žฌ๊ณ  ์„œ๋น„์Šค  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚             โ”‚     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚  order.     โ”‚
                    โ”‚  created    โ”‚โ”€โ”€โ”€โ”€โ†’โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚             โ”‚     โ”‚  ์•Œ๋ฆผ ์„œ๋น„์Šค  โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                           โ”‚
                           โ†“
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚  ๋ถ„์„ ์„œ๋น„์Šค  โ”‚
                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜


// ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ํ๋ฆ„
// 1. ์ฃผ๋ฌธ ์ƒ์„ฑ โ†’ order.created ๋ฐœํ–‰
// 2. ์žฌ๊ณ  ์„œ๋น„์Šค โ†’ ์žฌ๊ณ  ์ฐจ๊ฐ โ†’ inventory.updated ๋ฐœํ–‰
// 3. ๊ฒฐ์ œ ์„œ๋น„์Šค โ†’ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ โ†’ payment.completed ๋ฐœํ–‰
// 4. ์•Œ๋ฆผ ์„œ๋น„์Šค โ†’ ์ด๋ฉ”์ผ/ํ‘ธ์‹œ ๋ฐœ์†ก
// 5. ๋ถ„์„ ์„œ๋น„์Šค โ†’ ๋ฐ์ดํ„ฐ ์ €์žฅ


์‹ค์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ


โœ… ๋ฉ”์‹œ์ง€ ์„ค๊ณ„


  • ๋ฉ”์‹œ์ง€ ์Šคํ‚ค๋งˆ ์ •์˜
  • ๋ฒ„์ „ ๊ด€๋ฆฌ ๊ณ ๋ ค
  • ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ํฌํ•จ
  • ๋ฉฑ๋“ฑ์„ฑ ํ‚ค ํฌํ•จ


โœ… ์‹ ๋ขฐ์„ฑ


  • ๋ฉ”์‹œ์ง€ ์˜์†์„ฑ ์„ค์ •
  • ACK ์ „๋žต ๊ฒฐ์ •
  • ์žฌ์‹œ๋„ ๋กœ์ง ๊ตฌํ˜„
  • DLQ ์„ค์ •


โœ… ์„ฑ๋Šฅ


  • ํŒŒํ‹ฐ์…˜ ์ˆ˜ ๊ฒฐ์ • (Kafka)
  • Consumer Group ์„ค๊ณ„
  • ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ๊ณ ๋ ค
  • ๋ชจ๋‹ˆํ„ฐ๋ง ์„ค์ •


โœ… ์šด์˜


  • ๋ฉ”์‹œ์ง€ ์ถ”์  ๊ฐ€๋Šฅ
  • ์•Œ๋ฆผ ์„ค์ •
  • ๋ฐฑ์—… ์ „๋žต
  • ์žฅ์•  ๋Œ€์‘ ๊ณ„ํš


์š”์•ฝ


๋ฉ”์‹œ์ง€ ํ๋Š” ์‹œ์Šคํ…œ ๊ฐ„ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š” ํ•ต์‹ฌ ์ธํ”„๋ผ๋‹ค.

๐Ÿ’Ž ํ•ต์‹ฌ ํฌ์ธํŠธ:

  1. Producer: ๋ฉ”์‹œ์ง€ ๋ฐœํ–‰
  2. Queue/Topic: ๋ฉ”์‹œ์ง€ ์ €์žฅ
  3. Consumer: ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ
  4. P2P: ํ•˜๋‚˜์˜ Consumer๋งŒ ์ฒ˜๋ฆฌ
  5. Pub/Sub: ๋ชจ๋“  ๊ตฌ๋…์ž๊ฐ€ ์ˆ˜์‹ 
  6. ACK: ์ฒ˜๋ฆฌ ์™„๋ฃŒ ํ™•์ธ


๐Ÿ“Œ ์„ ํƒ ๊ธฐ์ค€:

์ƒํ™ฉ ๊ถŒ์žฅ
์ž‘์—… ํ RabbitMQ
์ด๋ฒคํŠธ ์ŠคํŠธ๋ฆฌ๋ฐ Kafka
์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ RabbitMQ
๋กœ๊ทธ ์ˆ˜์ง‘ Kafka
๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๋‘˜ ๋‹ค ๊ฐ€๋Šฅ


๐Ÿš€ Best Practices:

  • ๋ฉฑ๋“ฑ์„ฑ ๋ณด์žฅ ํ•„์ˆ˜
  • DLQ๋กœ ์‹คํŒจ ๋ฉ”์‹œ์ง€ ๊ด€๋ฆฌ
  • ๋ฉ”์‹œ์ง€ ์Šคํ‚ค๋งˆ ๋ฒ„์ „ ๊ด€๋ฆฌ
  • Consumer Group์œผ๋กœ ํ™•์žฅ
  • ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์•Œ๋ฆผ ์„ค์ •
  • ์žฌ์‹œ๋„ ์ „๋žต ์ˆ˜๋ฆฝ


๋ฉ”์‹œ์ง€ ํ๋ฅผ ์ž˜ ํ™œ์šฉํ•˜๋ฉด,
์‹œ์Šคํ…œ ๊ฐ„ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๊ณ ,
ํ™•์žฅ์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.