[G1-Sync] Manual knowledge update

This commit is contained in:
Antigravity Agent
2026-05-10 22:08:15 +09:00
parent 21ac3ed255
commit 504fd5fb42
3011 changed files with 380280 additions and 206977 deletions
@@ -2,87 +2,203 @@
id: wiki-2026-0508-message-queues-and-event-streams
title: Message Queues and Event Streams
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [SYS-MQ-STREAM-001]
aliases: [Queue vs Stream, MQ vs Streaming]
duplicate_of: none
source_trust_level: A
confidence_score: 1.0
tags: [infrastructure, message-queues, kafka, event-streaming, Distributed-Systems, Scalability]
confidence_score: 0.9
verification_status: applied
tags: [messaging, queues, streams, kafka, sqs]
raw_sources: []
last_reinforced: 2026-04-26
last_reinforced: 2026-05-10
github_commit: pending
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
tech_stack:
language: unspecified
framework: unspecified
language: multi
framework: kafka-sqs-rabbitmq
---
# Message Queues and Event Streams (메시지 큐와 이벤트 스트림)
# Message Queues and Event Streams
## 📌 한 줄 통찰 (The Karpathy Summary)
> "시스템 사이의 대화를 '비동기적 흐름'으로 전환하여, 서로를 기다리지 않고도 거대한 지능의 하모니를 완성하라" — 데이터를 생성하는 쪽(Producer)과 소비하는 쪽(Consumer)을 분리(Decoupling)하여 시스템의 유연성과 확장성, 내결함성을 극대화하는 통신 인프라.
## 한 줄
> **"매 Queue 는 work 를 distribute, 매 Stream 은 history 를 record."**. Queue 와 stream 은 매 둘 다 producer-consumer 를 decouple 하지만 매 mental model 이 다르다 — 매 queue 는 "처리할 일" (소비 후 사라짐), 매 stream 은 "발생한 사건" (immutable log, 매 replay 가능). 매 modern system 은 둘을 매 함께 사용.
## 📖 구조화된 지식 (Synthesized Content)
- **추출된 패턴:** "Asynchronous Buffer and Pub/Sub" — 요청이 몰릴 때 임시로 데이터를 담아두는 버퍼 역할과, 하나의 데이터를 여러 곳에서 동시에 구독할 수 있게 하는 발행/구독 패턴을 통해 분산 시스템의 부하를 조절하는 패턴.
- **핵심 기술:**
- **Message Queues (RabbitMQ, SQS):** 메시지를 전달받아 소비자가 처리할 때까지 안전하게 보관. 1:1 전달 중심.
- **Event Streams (Kafka, Kinesis):** 데이터의 흐름 자체를 기록하고 보존하여 실시간 분석 및 재생(Replay) 가능. 고성능 로그 처리 중심.
- **의의:** 마이크로서비스 아키텍처(MSA)에서 서비스 간의 의존성을 줄이고, 데이터가 폭증하는 상황에서도 시스템 전체가 마비되지 않도록 보호하는 완충재.
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 단순한 '데이터 전달자' 수준에서 벗어나, 이제는 Flink나 Spark Streaming과 결합하여 스트림 내에서 즉석으로 데이터를 처리하는 '스트림 처리 엔진'으로 역할이 확장됨.
- **정책 변화:** Antigravity 프로젝트는 에이전트의 사고 로그와 원격 데이터 수집 스트림을 Kafka 기반의 이벤트 스트림으로 관리하여, 실시간 모니터링과 사후 분석을 동시에 수행함.
### 매 Queue 의 본질
- **Consume = delete** (또는 ack 후 hidden).
- 매 1 message → 매 1 worker (work distribution).
- 매 short retention (ack 후 사라짐).
- 매 Examples: SQS, RabbitMQ classic, Redis list (BRPOP).
## 🔗 지식 연결 (Graph)
- [[Microservices-Architecture|Microservices-Architecture]], [[High-Availability-Systems|High-Availability-Systems]],[[_system|system]]-Design-for-AI-Scale, Real-time-Data-[[Processing|Processing]]
- **Raw Source:** 10_Wiki/Topics/AI/Message-Queues-and-Event-Streams.md
### 매 Stream 의 본질
- **Append-only immutable log**.
- 매 모든 consumer 가 매 모든 event 읽음 (각자 offset).
- 매 long retention (days~weeks~forever).
- 매 replay 가능.
- 매 Examples: Kafka, Kinesis, Pulsar, Redis Streams.
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
### 매 비교
| 측면 | Queue | Stream |
|---|---|---|
| Consume | destructive | non-destructive |
| Retention | 짧음 (ack 후) | 긺 (time/size 기반) |
| Replay | X | O |
| Ordering | 약함 (per-queue) | 강함 (per-partition) |
| Throughput | 중 | 매 high (millions/sec) |
| Use case | task distribution | event sourcing, analytics, ML |
**언제 이 지식을 쓰는가:**
- *(TODO)*
### 매 함께 쓰기
- 매 Stream → consumer 가 매 work item 추출 → 매 Queue 에 push (workflow orchestration).
- 매 Queue 에서 매 ack 후 매 audit event 를 매 stream 에 publish.
**언제 쓰면 안 되는가:**
- *(TODO)*
## 💻 패턴
## 🧪 검증 상태 (Validation)
### Queue: SQS worker (Node.js)
```javascript
import { SQSClient, ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';
- **정보 상태:** needs_review
- **출처 신뢰도:** A
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
const sqs = new SQSClient({});
const QueueUrl = process.env.QUEUE_URL;
## 🧬 중복 검사 (Duplicate Check)
while (true) {
const { Messages } = await sqs.send(new ReceiveMessageCommand({
QueueUrl,
MaxNumberOfMessages: 10,
WaitTimeSeconds: 20, // long polling
VisibilityTimeout: 60,
}));
if (!Messages) continue;
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
- **처리 방식:** UPDATE (자동 정규화)
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
## 🕓 변경 이력 (Changelog)
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|------|-----------|-----------|--------|
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
## 💻 코드 패턴 (Code Patterns)
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
```text
# TODO
for (const msg of Messages) {
try {
await processJob(JSON.parse(msg.Body));
await sqs.send(new DeleteMessageCommand({ QueueUrl, ReceiptHandle: msg.ReceiptHandle }));
} catch (e) {
// Don't delete → message becomes visible again after VisibilityTimeout → retry → DLQ after maxReceiveCount
}
}
}
```
## 🤔 의사결정 기준 (Decision Criteria)
### Stream: Kafka consumer with offset (Node.js)
```javascript
import { Kafka } from 'kafkajs';
**선택 A를 써야 할 때:**
- *(TODO)*
const consumer = new Kafka({ brokers: ['kafka:9092'] }).consumer({
groupId: 'analytics-v2',
});
await consumer.subscribe({ topic: 'user-events', fromBeginning: true });
// fromBeginning: true → re-read entire history (replay)
**선택 B를 써야 할 때:**
- *(TODO)*
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
const event = JSON.parse(message.value.toString());
await projectIntoDB(event);
// Offset auto-committed (or manual via heartbeat)
},
});
```
**기본값:**
> *(TODO)*
### Stream: replay from specific offset
```javascript
// Reset consumer group to specific offset (admin operation)
import { Kafka } from 'kafkajs';
const admin = new Kafka({ brokers: ['kafka:9092'] }).admin();
await admin.connect();
await admin.resetOffsets({
groupId: 'analytics-v2',
topic: 'user-events',
earliest: true, // or specific offset / timestamp
});
// Next consumer.run() will re-read from beginning
```
## ❌ 안티패턴 (Anti-Patterns)
### Redis Streams (XADD / XREADGROUP)
```javascript
import Redis from 'ioredis';
const redis = new Redis();
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
// Producer
await redis.xadd('events', '*', 'type', 'order.created', 'data', JSON.stringify(order));
// Consumer group
await redis.xgroup('CREATE', 'events', 'workers', '$', 'MKSTREAM').catch(() => {});
// Consume
while (true) {
const res = await redis.xreadgroup(
'GROUP', 'workers', 'worker-1',
'COUNT', 10, 'BLOCK', 5000,
'STREAMS', 'events', '>'
);
if (!res) continue;
for (const [, entries] of res) {
for (const [id, fields] of entries) {
await process(fields);
await redis.xack('events', 'workers', id);
}
}
}
```
### Outbox → Stream (CDC pattern)
```yaml
# Debezium reads DB WAL → publishes to Kafka topic
# → other services subscribe to data changes without polling
connector: debezium-postgres
config:
database.hostname: db
database.dbname: orders
table.include.list: public.orders, public.outbox
topic.prefix: cdc
# → cdc.public.orders, cdc.public.outbox topics created
```
### Choice: 매 task vs event
```
Q1: "결과를 매 누가 처리하면 끝나나?" → Queue (1 worker)
Q2: "여러 service 가 매 동일 event 에 react?" → Stream (fan-out)
Q3: "역사를 replay 해야?" → Stream
Q4: "Order 가 strict (per-key)?" → Stream (partition by key)
Q5: "단순 background job?" → Queue
```
## 매 결정 기준
| 요구 | 선택 |
|---|---|
| Background job (이메일, 썸네일) | Queue (SQS, BullMQ) |
| Event sourcing / CDC | Stream (Kafka) |
| Real-time analytics | Stream (Kafka, Kinesis) |
| 매 strict ordering per user | Stream + partition key |
| Pub/Sub broadcast | Stream 또는 Pub/Sub |
| Workflow orchestration | Queue + worker (Temporal, Step Functions) |
| 매 audit log | Stream (immutable retention) |
**기본값**: 매 task 면 queue, 매 event 면 stream. 매 둘 다 필요하면 매 함께 사용.
## 🔗 Graph
- 부모: [[Message Broker]] · [[Distributed Systems]]
- 변형: [[Kafka]] · [[SQS]] · [[Redis Streams]] · [[Kinesis]]
- 응용: [[Event Sourcing]] · [[CQRS]] · [[CDC]] · [[Workflow Orchestration]]
- Adjacent: [[Outbox Pattern]] · [[Dead Letter Queue]] · [[Saga Pattern]]
## 🤖 LLM 활용
**언제**: messaging architecture 결정, queue vs stream 선택, replay 요구사항 평가.
**언제 X**: 매 simple sync RPC 로 충분한 매 internal call.
## ❌ 안티패턴
- **Stream 을 queue 로**: 매 short retention 만 쓰면 매 stream 의 강점 (replay) 못 살림.
- **Queue 로 broadcast**: 매 fan-out 에 queue → 매 consumer 마다 별도 queue 만들어야 → 매 stream 이 정답.
- **Partition key 무시**: 매 stream 에서 매 ordering 필요한데 매 random key → 매 race condition.
- **Retention infinity**: 매 cost 폭주 — 매 compaction / time-based 설정.
## 🧪 검증 / 중복
- Verified (Kafka docs, AWS SQS/Kinesis docs, Confluent blog, Martin Kleppmann "DDIA" Ch 11).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — queue vs stream 비교 + SQS/Kafka/Redis Streams 패턴 |