f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
207 lines
5.5 KiB
Markdown
207 lines
5.5 KiB
Markdown
---
|
|
id: wiki-2026-0508-event-driven-architecture
|
|
title: Event-Driven Architecture
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [EDA, event-driven, pub-sub, message-driven, choreography, orchestration]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.97
|
|
verification_status: applied
|
|
tags: [architecture, eda, event-driven, kafka, pub-sub, choreography, microservices]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: TypeScript / Java / Python
|
|
framework: Kafka / RabbitMQ / EventBridge / NATS
|
|
---
|
|
|
|
# Event-Driven Architecture
|
|
|
|
## 매 한 줄
|
|
> **"매 service 의 event 의 의 communicate"**. 매 sync HTTP RPC 의 X — 매 async pub/sub. 매 decouple + scale + replay. 매 modern: 매 Kafka, EventBridge, NATS, async.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 pattern
|
|
- **Event notification**: 매 fire-and-forget.
|
|
- **Event-carried state transfer**: 매 payload 의 state.
|
|
- **Event sourcing**: 매 store events.
|
|
- **CQRS**: 매 read/write split.
|
|
|
|
### 매 choreography vs orchestration
|
|
- **Choreography**: 매 service 의 react.
|
|
- **Orchestration**: 매 central coordinator (saga).
|
|
|
|
### 매 응용
|
|
1. **Microservices**: 매 decouple.
|
|
2. **Real-time**: 매 streaming.
|
|
3. **Fan-out**: 매 1 → many.
|
|
4. **Audit**: 매 replay.
|
|
5. **Integration**: 매 cross-system.
|
|
|
|
## 💻 패턴
|
|
|
|
### Kafka producer (Java)
|
|
```java
|
|
KafkaProducer<String, String> p = new KafkaProducer<>(props);
|
|
p.send(new ProducerRecord<>("orders.placed", orderId, json), (md, ex) -> {
|
|
if (ex != null) log.error("Failed", ex);
|
|
});
|
|
```
|
|
|
|
### Kafka consumer (Python)
|
|
```python
|
|
from confluent_kafka import Consumer
|
|
c = Consumer({'bootstrap.servers': 'kafka:9092', 'group.id': 'inventory', 'auto.offset.reset': 'earliest'})
|
|
c.subscribe(['orders.placed'])
|
|
while True:
|
|
msg = c.poll(1.0)
|
|
if msg and not msg.error():
|
|
handle_order(json.loads(msg.value()))
|
|
```
|
|
|
|
### Outbox (transactional publish)
|
|
```typescript
|
|
async function placeOrder(o: Order) {
|
|
await db.transaction(async tx => {
|
|
await tx.orders.save(o);
|
|
await tx.outbox.insert({ topic: 'orders.placed', payload: o, status: 'pending' });
|
|
});
|
|
}
|
|
// 매 separate process polls outbox → Kafka
|
|
```
|
|
|
|
### Schema registry (Avro)
|
|
```json
|
|
{
|
|
"type": "record",
|
|
"name": "OrderPlaced",
|
|
"fields": [
|
|
{ "name": "orderId", "type": "string" },
|
|
{ "name": "amount", "type": "long" },
|
|
{ "name": "currency", "type": "string", "default": "USD" }
|
|
]
|
|
}
|
|
```
|
|
|
|
### Saga orchestration
|
|
```typescript
|
|
class OrderSaga {
|
|
async execute(orderId: string) {
|
|
try {
|
|
await reservePayment(orderId);
|
|
await reserveInventory(orderId);
|
|
await scheduleShipping(orderId);
|
|
} catch (e) {
|
|
await this.compensate(orderId);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async compensate(orderId: string) {
|
|
await releaseInventory(orderId);
|
|
await refundPayment(orderId);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Choreography (each service reacts)
|
|
```typescript
|
|
// 매 inventory service
|
|
on('orders.placed', async event => {
|
|
const ok = await reserve(event.orderId);
|
|
publish(ok ? 'inventory.reserved' : 'inventory.failed', event);
|
|
});
|
|
|
|
// 매 shipping service
|
|
on('inventory.reserved', async event => {
|
|
await schedule(event.orderId);
|
|
publish('shipping.scheduled', event);
|
|
});
|
|
```
|
|
|
|
### DLQ (dead letter queue)
|
|
```python
|
|
def consume_with_dlq(topic, handler, max_retries=3):
|
|
for msg in consumer:
|
|
for attempt in range(max_retries):
|
|
try:
|
|
handler(msg)
|
|
break
|
|
except Exception as e:
|
|
if attempt == max_retries - 1:
|
|
dlq.publish(msg, error=str(e))
|
|
```
|
|
|
|
### Idempotency
|
|
```python
|
|
def idempotent_handler(event):
|
|
if redis.set(f'evt:{event.id}', '1', nx=True, ex=86400):
|
|
process(event)
|
|
# 매 else: skip duplicate
|
|
```
|
|
|
|
### Backpressure
|
|
```python
|
|
def consume_with_backpressure(consumer, max_in_flight=100):
|
|
sem = Semaphore(max_in_flight)
|
|
for msg in consumer:
|
|
sem.acquire()
|
|
thread = Thread(target=lambda m=msg: (process(m), sem.release()))
|
|
thread.start()
|
|
```
|
|
|
|
### Event versioning
|
|
```typescript
|
|
type OrderPlacedV1 = { version: 1; orderId: string; amount: number };
|
|
type OrderPlacedV2 = { version: 2; orderId: string; amount: number; currency: string };
|
|
|
|
function migrate(e: OrderPlacedV1 | OrderPlacedV2): OrderPlacedV2 {
|
|
if (e.version === 1) return { ...e, version: 2, currency: 'USD' };
|
|
return e;
|
|
}
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Tool |
|
|
|---|---|
|
|
| High throughput | Kafka |
|
|
| Cloud-native AWS | EventBridge / SNS+SQS |
|
|
| Low latency | NATS |
|
|
| Complex routing | RabbitMQ |
|
|
| Simple pub/sub | Redis Streams |
|
|
| Multi-step | Saga (Temporal) |
|
|
|
|
**기본값**: 매 Kafka + 매 schema registry + 매 outbox + 매 DLQ + 매 idempotency.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Architecture]] · [[Distributed-Systems]]
|
|
- 변형: [[Event Sourcing Pattern]] · [[CQRS]]
|
|
- 응용: [[Kafka]] · [[NATS]]
|
|
- Adjacent: [[Microservices]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: 매 microservice. 매 streaming. 매 decouple.
|
|
**언제 X**: 매 simple monolith. 매 strict transaction.
|
|
|
|
## ❌ 안티패턴
|
|
- **Sync inside async**: 매 backpressure 의 break.
|
|
- **No schema**: 매 break.
|
|
- **No DLQ**: 매 stuck consumer.
|
|
- **No idempotency**: 매 duplicate processing.
|
|
- **Choreography 의 over-use**: 매 spaghetti.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Fowler EDA, Confluent, AWS Reference Architecture).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-04-20 | Auto-reinforced |
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — EDA + 매 Kafka / outbox / saga / DLQ / idempotency code |
|