--- id: wiki-2026-0508-message-broker title: Message Broker category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Message Brokers, MQ, Event Broker, Pub-Sub Broker] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [messaging, distributed, kafka, rabbitmq, nats] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: multi framework: kafka-rabbitmq-nats --- # Message Broker ## 매 한 줄 > **"매 producer 와 consumer 사이의 매 async middleman."**. Message broker 는 매 service 간 매 decouple, 매 buffering, 매 fan-out 을 제공하는 매 infrastructure. 매 2026 의 big three 는 매 Kafka (event streaming), 매 RabbitMQ (traditional queue), 매 NATS (lightweight low-latency). 매 cloud-native 는 SQS / Pub/Sub / EventBridge 도 매 흔함. ## 매 핵심 ### 매 왜 broker - **Decoupling**: producer 가 consumer 의 위치/존재 모름. - **Buffering**: spike 흡수 — consumer 가 천천히 처리. - **Fan-out**: 1 message → N consumer. - **Reliability**: persistent queue → consumer crash 후 replay. - **Async**: producer 가 response 안 기다림. ### 매 model - **Queue (point-to-point)**: 1 message → 1 consumer (load balance). - **Pub/Sub (topic)**: 1 message → N subscriber (broadcast). - **Event log**: 매 immutable append-only — replay/time-travel (Kafka). ### 매 보장 - **At-most-once**: 매 fast, 매 loss 가능. - **At-least-once**: 매 default, 매 duplicate 가능 → idempotent consumer 필요. - **Exactly-once**: 매 어렵 (Kafka EoS transactions, idempotent producer + transactional consumer). ### 매 Kafka 핵심 - **Topic** → **Partition** (parallelism unit) → **Offset**. - 매 Consumer group 으로 partition load balance. - 매 retention (time / size) — log 그대로 저장. - 매 replay 가능 — offset reset. ### 매 RabbitMQ 핵심 - **Exchange** (direct/topic/fanout/headers) → **Binding** → **Queue**. - 매 AMQP 0.9.1 (현재) / AMQP 1.0 / MQTT / STOMP. - 매 ack/nack, dead-letter exchange. - 매 message TTL, priority queue. ### 매 NATS 핵심 - 매 lightweight, sub-ms latency. - 매 Core NATS (fire-and-forget) + JetStream (persistence + at-least-once). - 매 subject hierarchy: `orders.eu.de`. ## 💻 패턴 ### Kafka producer/consumer (Node.js, kafkajs) ```javascript import { Kafka } from 'kafkajs'; const kafka = new Kafka({ brokers: ['kafka:9092'], clientId: 'orders-svc' }); // Producer const producer = kafka.producer({ idempotent: true }); // exactly-once-ish await producer.connect(); await producer.send({ topic: 'orders', messages: [{ key: order.userId, // partition key → ordering per user value: JSON.stringify(order), }], }); // Consumer const consumer = kafka.consumer({ groupId: 'fulfillment' }); await consumer.subscribe({ topic: 'orders', fromBeginning: false }); await consumer.run({ eachMessage: async ({ message }) => { const order = JSON.parse(message.value.toString()); await fulfill(order); // must be idempotent }, }); ``` ### RabbitMQ (Node.js, amqplib) ```javascript import amqp from 'amqplib'; const conn = await amqp.connect('amqp://localhost'); const ch = await conn.createChannel(); // Topic exchange + DLX await ch.assertExchange('orders', 'topic', { durable: true }); await ch.assertQueue('fulfillment', { durable: true, deadLetterExchange: 'orders.dlx', }); await ch.bindQueue('fulfillment', 'orders', 'order.created.*'); // Publish ch.publish('orders', 'order.created.eu', Buffer.from(JSON.stringify(order)), { persistent: true }); // Consume with manual ack ch.consume('fulfillment', async (msg) => { try { await fulfill(JSON.parse(msg.content.toString())); ch.ack(msg); } catch (e) { ch.nack(msg, false, false); // → DLX } }, { noAck: false }); ``` ### NATS JetStream (Node.js) ```javascript import { connect, JSONCodec } from 'nats'; const nc = await connect({ servers: 'nats://localhost:4222' }); const js = nc.jetstream(); const jc = JSONCodec(); // Producer await js.publish('orders.created.eu', jc.encode(order)); // Durable consumer const sub = await js.subscribe('orders.>', { config: { durable_name: 'fulfillment', ack_policy: 'explicit' }, }); for await (const m of sub) { await fulfill(jc.decode(m.data)); m.ack(); } ``` ### Idempotent consumer (deduplication) ```javascript async function handleMessage(msg) { const id = msg.headers['message-id']; // Try insert into processed table — unique constraint on id const inserted = await db.query( 'INSERT INTO processed (id, ts) VALUES ($1, NOW()) ON CONFLICT DO NOTHING', [id] ); if (inserted.rowCount === 0) return; // already processed await businessLogic(msg); } ``` ### Outbox pattern (transactional publish) ```sql -- Same DB transaction: write business state + outbox entry BEGIN; UPDATE orders SET status='paid' WHERE id=$1; INSERT INTO outbox (topic, payload, ts) VALUES ('orders.paid', $2, NOW()); COMMIT; -- Separate process: poll outbox → publish to broker → mark sent ``` ## 매 결정 기준 | 상황 | Broker | |---|---| | Event streaming, replay, analytics | Kafka | | Complex routing, traditional queue | RabbitMQ | | Sub-ms latency, microservices | NATS | | AWS-native, simple | SQS + SNS | | GCP-native | Pub/Sub | | Azure-native | Service Bus / Event Hubs | | Single-process / dev | Redis Streams, in-memory | **기본값**: 매 cloud-native team → managed (SQS/Pub-Sub). 매 self-host + event log → Kafka. 매 traditional queue → RabbitMQ. ## 🔗 Graph - 부모: [[Distributed Systems]] · [[Event-Driven Architecture]] - 변형: [[Kafka]] · [[RabbitMQ]] · [[NATS]] · [[SQS]] · [[Pub-Sub]] - 응용: [[Microservices]] · [[Event Sourcing]] · [[CQRS]] - Adjacent: [[Message-Queues-and-Event-Streams]] · [[Dead Letter Queue]] ## 🤖 LLM 활용 **언제**: service decoupling, async workflow, event-driven design, spike absorption. **언제 X**: 매 simple sync RPC 면 충분 — 매 broker = operational overhead. ## ❌ 안티패턴 - **At-most-once 로 critical data**: 매 loss 허용 안되면 매 ack 필수. - **No idempotency**: 매 at-least-once 에서 매 duplicate → side effect 2번. - **Big payload**: 매 broker 에 large blob → 매 S3 reference 패턴 사용. - **No DLQ**: 매 poison message 가 매 무한 retry → consumer 마비. - **Kafka 를 queue 로**: 매 ordering 만 필요한 매 short job → RabbitMQ 가 더 적합. ## 🧪 검증 / 중복 - Verified (Apache Kafka docs, RabbitMQ docs, NATS docs, Confluent blog, Microservices.io patterns). - 신뢰도 A. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — Kafka/RabbitMQ/NATS 비교 + outbox/idempotent 패턴 |