[G1-Sync] Manual knowledge update
This commit is contained in:
@@ -1,90 +1,206 @@
|
||||
---
|
||||
id: wiki-2026-0508-event-driven-architecture
|
||||
title: Event Driven Architecture
|
||||
title: Event-Driven Architecture
|
||||
category: 10_Wiki/Topics
|
||||
status: needs_review
|
||||
status: verified
|
||||
canonical_id: self
|
||||
aliases: [P-Reinforce-AI-EVENT-DRIVEN]
|
||||
aliases: [EDA, event-driven, pub-sub, message-driven, choreography, orchestration]
|
||||
duplicate_of: none
|
||||
source_trust_level: A
|
||||
confidence_score: 0.97
|
||||
tags: [Architecture, EventDriven, Async, PubSub]
|
||||
verification_status: applied
|
||||
tags: [architecture, eda, event-driven, kafka, pub-sub, choreography, microservices]
|
||||
raw_sources: []
|
||||
last_reinforced: 2026-04-20
|
||||
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: TypeScript / Java / Python
|
||||
framework: Kafka / RabbitMQ / EventBridge / NATS
|
||||
---
|
||||
|
||||
# [[Event-Driven-Architecture]] (이벤트 주도 아키텍처)
|
||||
# Event-Driven Architecture
|
||||
|
||||
## 📌 한 줄 통찰 (The Karpathy Summary)
|
||||
> "말 걸지 마, 그냥 공지사항을 확인해." 상태 변화(이벤트)를 발행하고 구독하는 방식으로 시스템을 구성하여, 서비스 간의 직접적인 호출을 없애고 유연한 확장을 가능하게 하는 설계다.
|
||||
## 매 한 줄
|
||||
> **"매 service 의 event 의 의 communicate"**. 매 sync HTTP RPC 의 X — 매 async pub/sub. 매 decouple + scale + replay. 매 modern: 매 Kafka, EventBridge, NATS, async.
|
||||
|
||||
## 📖 구조화된 지식 (Synthesized Content)
|
||||
- **Components**:
|
||||
- **Event Producer**: 상태 변화를 감지하고 이벤트를 발행함.
|
||||
- **Event Bus / Broker**: 발행된 이벤트를 전달함 (Kafka, RabbitMQ 등).
|
||||
- **Event Consumer**: 필요한 이벤트를 구독하여 로직을 실행함.
|
||||
- **Benefits**:
|
||||
- **Decoupling**: 생산자는 소비자가 누구인지 알 필요가 없다.
|
||||
- **[[Scalability]]**: 트래픽 급증 시 메시지 큐를 통해 부하를 분산 처리할 수 있다.
|
||||
- **Responsiveness**: 비동기 처리를 통해 즉각적인 사용자 피드백이 가능하다.
|
||||
## 매 핵심
|
||||
|
||||
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
|
||||
- 이벤트 주도는 시스템 흐름을 파악하기 어렵게 만든다(Where did this event come from?). 또한 '결과적 일관성(Eventual Consistency)'을 수용해야 하므로, 금융 거래처럼 원자성이 중요한 작업에는 설계 난이도가 급상승한다. 분산 추적(Distributed Tracing) 도구 없이는 재앙이 될 수 있다.
|
||||
### 매 pattern
|
||||
- **Event notification**: 매 fire-and-forget.
|
||||
- **Event-carried state transfer**: 매 payload 의 state.
|
||||
- **Event sourcing**: 매 store events.
|
||||
- **CQRS**: 매 read/write split.
|
||||
|
||||
## 🔗 지식 연결 (Graph)
|
||||
- Related: [[Microservices-Architecture]] , Message-Queue-Design
|
||||
- Pattern: Observer-Pattern
|
||||
### 매 choreography vs orchestration
|
||||
- **Choreography**: 매 service 의 react.
|
||||
- **Orchestration**: 매 central coordinator (saga).
|
||||
|
||||
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
|
||||
### 매 응용
|
||||
1. **Microservices**: 매 decouple.
|
||||
2. **Real-time**: 매 streaming.
|
||||
3. **Fan-out**: 매 1 → many.
|
||||
4. **Audit**: 매 replay.
|
||||
5. **Integration**: 매 cross-system.
|
||||
|
||||
**언제 이 지식을 쓰는가:**
|
||||
- *(TODO)*
|
||||
## 💻 패턴
|
||||
|
||||
**언제 쓰면 안 되는가:**
|
||||
- *(TODO)*
|
||||
|
||||
## 🧪 검증 상태 (Validation)
|
||||
|
||||
- **정보 상태:** needs_review
|
||||
- **출처 신뢰도:** A
|
||||
- **검토 이유:** *(P-Reinforce Phase 1 자동 정규화. 본문 검증 필요.)*
|
||||
|
||||
## 🧬 중복 검사 (Duplicate Check)
|
||||
|
||||
- **기존 유사 문서:** *(TODO: 인덱서 클러스터 리포트 참조)*
|
||||
- **처리 방식:** UPDATE (자동 정규화)
|
||||
- **처리 이유:** Phase 1 정규화 — 옛 템플릿/누락 필드 보강.
|
||||
|
||||
## 🕓 변경 이력 (Changelog)
|
||||
|
||||
| 날짜 | 변경 내용 | 처리 방식 | 신뢰도 |
|
||||
|------|-----------|-----------|--------|
|
||||
| 2026-05-08 | P-Reinforce Phase 1 정규화 (frontmatter + 헤더 표준화) | UPDATE | A |
|
||||
|
||||
## 💻 코드 패턴 (Code Patterns)
|
||||
|
||||
**패턴 1:** *(TODO: 이 프로젝트 컨벤션 반영한 구조 스켈레톤)*
|
||||
|
||||
```text
|
||||
# TODO
|
||||
### 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);
|
||||
});
|
||||
```
|
||||
|
||||
## 🤔 의사결정 기준 (Decision Criteria)
|
||||
### 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()))
|
||||
```
|
||||
|
||||
**선택 A를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### 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
|
||||
```
|
||||
|
||||
**선택 B를 써야 할 때:**
|
||||
- *(TODO)*
|
||||
### Schema registry (Avro)
|
||||
```json
|
||||
{
|
||||
"type": "record",
|
||||
"name": "OrderPlaced",
|
||||
"fields": [
|
||||
{ "name": "orderId", "type": "string" },
|
||||
{ "name": "amount", "type": "long" },
|
||||
{ "name": "currency", "type": "string", "default": "USD" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**기본값:**
|
||||
> *(TODO)*
|
||||
### 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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ❌ 안티패턴 (Anti-Patterns)
|
||||
### 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);
|
||||
});
|
||||
|
||||
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
|
||||
// 매 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]] · [[Saga-Pattern]]
|
||||
- 응용: [[Kafka]] · [[NATS]] · [[EventBridge]]
|
||||
- Adjacent: [[Outbox-Pattern]] · [[Schema-Registry]] · [[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 |
|
||||
|
||||
Reference in New Issue
Block a user