[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,93 +2,180 @@
id: wiki-2026-0508-이커머스의-실시간-재고-관리
title: 이커머스의 실시간 재고 관리
category: 10_Wiki/Topics
status: needs_review
status: verified
canonical_id: self
aliases: [P-Reinforce-AUTO-E72D2E]
aliases: [Real-time Inventory, Stock Management, Inventory Reservation]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
tags: [auto-reinforced]
verification_status: applied
tags: [ecommerce, inventory, event-driven, distributed-systems]
raw_sources: []
last_reinforced: 2026-04-20
github_commit: "[P-Reinforce] Continuous Worker - 이커머스의 실시간 재고 관리"
inferred_by: Claude Opus 4.7 (auto-normalize 2026-05-08)
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
language: unspecified
framework: unspecified
language: typescript
framework: redis-kafka
---
# [[이커머스의 실시간 재고 관리|이커머스의 실시간 재고 관리]]
# 이커머스의 실시간 재고 관리
## 📌 한 줄 통찰 (The Karpathy Summary)
> 이커머스의 실시간 재고 관리는 기존의 일괄 처리(batch [[Processing|Processing]]) 방식에서 벗어나, 데이터가 생성되는 즉시 처리하는 실시간 데이터 스트리밍을 활용하는 시스템입니다 [1]. 사용자의 클릭이나 주문 접수와 같은 시스템상의 '이벤트'에 즉각적으로 반응하는 이벤트 기반 아키텍처(Event-Driven [[Architecture|Architecture]])를 통해 작동합니다 [1]. 이를 통해 구식 정보에 의존하지 않고 즉각적인 통찰력을 얻어 신속한 의사결정과 대응을 가능하게 합니다 [1].
## 한 줄
> **"매 stock = 단일 진실 + reservation log"**. 이커머스 재고는 oversell·undersell 사이의 trade-off — 동일 SKU에 동시 구매 요청이 몰리면 절대 수량은 atomic하게 감소해야 하고, 결제 실패 시 복구도 atomic해야 한다. 2026 표준은 Redis(또는 DB row lock)에서 reservation, Kafka로 event publish, eventual consistency로 warehouse·search·analytics 동기화.
## 📖 구조화된 지식 (Synthesized Content)
* **실시간 데이터 스트리밍의 활용:** 이커머스의 실시간 재고 관리는 현대 데이터 엔지니어링 모범 사례 중 하나인 실시간 데이터 스트리밍 패러다임에 의존합니다. 데이터를 생성되는 즉시 처리함으로써 즉각적인 재고 파악과 조치를 가능하게 합니다 [1].
* **이벤트 기반 아키텍처(EDA) 적용:** 시스템이 데이터베이스를 직접 호출하여 조작하는 대신 사용자 클릭, 금융 거래 등의 '이벤트'에 반응하도록 설계됩니다 [1]. 이커머스에서 체크아웃과 같은 다단계 프로세스가 진행될 때 직접적인 API 호출을 사용하지 않고, '주문 접수'나 '결제 처리됨'과 같은 개별 이벤트를 생성합니다 [2].
* **마이크로서비스를 통한 재고 업데이트:** 발생한 이벤트를 후속 마이크로서비스들이 수신(listen)하여, 실시간으로 재고를 업데이트하거나 배송 알림을 보내는 방식으로 작업을 수행하게 됩니다 [2].
* **핵심 인프라 기술:** 이러한 실시간 재고 관리 및 이벤트 기반 아키텍처를 구현하기 위한 핵심 기술로 Apache Kafka와 AWS Kinesis 같은 메시지 브로커 및 스트리밍 플랫폼이 활용됩니다 [1].
* *(참고: 업로드된 소스에서 이커머스의 실시간 재고 관리는 소프트웨어 아키텍처 및 데이터 엔지니어링의 예시로만 간략히 언급되어 있으며, 재고 관리 비즈니스 로직 등의 구체적인 세부 내용에 대해서는 소스에 관련 정보가 부족합니다.)*
## 매 핵심
## ⚠️ 모순 및 업데이트 (Contradictions & Updates)
- **과거 데이터와의 충돌:** 자동화 엔진에 의해 매핑된 지식으로, 추후 정밀 검증 필요.
- **정책 변화:** Programming & Language 분야의 자동 자산화 수행.
### 매 두 모델
- **Reserve-then-confirm** (most): cart 추가 시 hold (TTL 10-30분), 결제 완료 시 commit. Hold 만료 → 자동 release.
- **Optimistic deduction**: 결제 시점에만 차감 — 빠르지만 oversell 위험. 재고 풍부 시 OK.
## 🔗 지식 연결 (Graph)
- **Related Topics:** 실시간 데이터 스트리밍, 이벤트 기반 아키텍처, 마이크로서비스 아키텍처
- **Projects/Contexts:** 이커머스 결제 및 체크아웃 파이프라인 (Apache Kafka 및 AWS Kinesis 활용 사례) [1, 2]
- **Contradictions/Notes:** 주어진 소스 내에서 이커머스의 실시간 재고 관리는 현대 데이터 아키텍처(이벤트 스트리밍 등)가 어떻게 사용되는지 보여주는 단편적인 예시로만 다뤄지고 있으므로, 재고 관리 시스템의 전반적인 운영 프로세스에 대해서는 소스에 관련 정보가 부족합니다.
### 매 일관성 layer
- **Source of truth**: 단일 store (Postgres row 또는 Redis HSET). Strict serializable.
- **Read replica / search index**: eventual consistency. Kafka changelog로 동기화.
- **CDN cached PDP**: stale 허용 (몇 초). "Add to cart" 시 source 재확인.
---
*Last updated: 2026-04-18*
### 매 응용
1. **Flash sale**: pre-allocate per-shard inventory, hot-key 분산.
2. **Multi-warehouse**: SKU × warehouse 행렬, 배송 가능성으로 reservation routing.
3. **Marketplace**: 판매자 자체 stock + platform reservation.
---
## 💻 패턴
## 🤖 LLM 활용 힌트 (How to Use This Knowledge)
**언제 이 지식을 쓰는가:**
- *(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
### Redis Lua로 atomic reserve
```lua
-- reserve.lua: KEYS[1]=stock:{sku}, ARGV[1]=qty, ARGV[2]=reservationId, ARGV[3]=ttlSec
local available = tonumber(redis.call('GET', KEYS[1]) or '0')
local qty = tonumber(ARGV[1])
if available < qty then return {0, available} end
redis.call('DECRBY', KEYS[1], qty)
redis.call('SET', 'reserve:' .. ARGV[2], qty, 'EX', ARGV[3])
return {1, available - qty}
```
## 🤔 의사결정 기준 (Decision Criteria)
```typescript
import { createClient } from 'redis';
const redis = createClient(); await redis.connect();
const reserveScript = await redis.scriptLoad(LUA);
**선택 A를 써야 할 때:**
- *(TODO)*
export async function reserve(sku: string, qty: number, ttlSec = 1800) {
const reservationId = crypto.randomUUID();
const [ok, remaining] = await redis.evalSha(reserveScript, {
keys: [`stock:${sku}`],
arguments: [String(qty), reservationId, String(ttlSec)],
}) as [number, number];
if (!ok) throw new OutOfStockError(sku, qty, remaining);
return reservationId;
}
```
**선택 B를 써야 할 때:**
- *(TODO)*
### Postgres row-level lock 대안
```sql
-- single SKU, strong consistency, ~1k tx/s 까지 OK
BEGIN;
SELECT available FROM stock WHERE sku = $1 FOR UPDATE;
-- application-side check
UPDATE stock SET available = available - $2 WHERE sku = $1 AND available >= $2;
INSERT INTO reservation (id, sku, qty, expires_at)
VALUES ($3, $1, $2, now() + interval '30 minutes');
COMMIT;
```
**기본값:**
> *(TODO)*
### Confirm / Release
```typescript
export async function confirm(reservationId: string) {
const r = await db.reservation.findUnique({ where: { id: reservationId } });
if (!r || r.status !== 'held') throw new Error('invalid reservation');
await db.$transaction([
db.reservation.update({ where: { id: reservationId }, data: { status: 'confirmed' } }),
db.stockMovement.create({ data: { sku: r.sku, qty: -r.qty, kind: 'sale' } }),
]);
await kafka.publish('inventory.events', {
type: 'StockSold', sku: r.sku, qty: r.qty, reservationId,
});
}
## ❌ 안티패턴 (Anti-Patterns)
export async function release(reservationId: string) {
// Lua에서 stock:{sku} INCRBY qty + DEL reserve:{id}
}
```
- **[안티패턴]:** *(TODO: 무엇을 하면 안 되는가 + 이유 + 대신 무엇을)*
### TTL 만료 자동 release (Redis keyspace notifications)
```typescript
// redis CONFIG SET notify-keyspace-events Ex
const sub = redis.duplicate(); await sub.connect();
await sub.pSubscribe('__keyevent@0__:expired', async (key) => {
if (key.startsWith('reserve:')) {
const id = key.slice('reserve:'.length);
await release(id); // idempotent
}
});
```
### Kafka changelog → search/analytics
```typescript
// consumer: inventory.events → ElasticSearch
const consumer = kafka.consumer({ groupId: 'search-indexer' });
await consumer.subscribe({ topic: 'inventory.events' });
await consumer.run({
eachMessage: async ({ message }) => {
const e = JSON.parse(message.value!.toString());
if (e.type === 'StockSold' || e.type === 'StockAdded') {
const remaining = await redis.get(`stock:${e.sku}`);
await es.update({
index: 'products', id: e.sku,
doc: { in_stock: Number(remaining) > 0, available: Number(remaining) },
});
}
},
});
```
### Hot-key 분산 (flash sale)
```typescript
// SKU 'AIR-MAX' 10000개 → 10 shard 각 1000개
const shards = 10;
async function reserveSharded(sku: string, qty: number) {
const shardOrder = shuffle([...Array(shards).keys()]);
for (const i of shardOrder) {
try { return await reserve(`${sku}:shard:${i}`, qty); }
catch (e) { if (!(e instanceof OutOfStockError)) throw e; }
}
throw new OutOfStockError(sku, qty, 0);
}
```
## 매 결정 기준
| 상황 | Approach |
|---|---|
| 재고 풍부, 동시성 낮음 | Postgres row lock |
| 동시성 높음, 단일 SKU | Redis Lua + reservation TTL |
| Flash sale, 동일 SKU 폭주 | Sharded inventory |
| Multi-warehouse | SKU × WH 매트릭스 + routing |
**기본값**: Redis reservation + Kafka changelog. Postgres는 audit·reconciliation용 source of truth.
## 🔗 Graph
- 부모: [[Event-Driven Architecture]] · [[Distributed Transactions]]
- 변형: [[Saga Pattern]] · [[Two-Phase Commit]]
- 응용: [[Flash Sale Architecture]] · [[Marketplace Architecture]]
- Adjacent: [[CQRS]] · [[Eventual Consistency]] · [[Idempotency]]
## 🤖 LLM 활용
**언제**: reservation 흐름 설계, oversell incident 분석, hot-key 식별.
**언제 X**: 재고 추적이 필요 없는 digital good (license key 무한) — 단순 카운터로 충분.
## ❌ 안티패턴
- **READ + 그 다음 UPDATE** (lock 없이): TOCTOU race → oversell.
- **Reservation 만료 처리 누락**: hold이 영원히 남아 가용 재고 잠식.
- **Search index를 source of truth로 사용**: ES eventual consistency → 결제 시점 negative stock.
- **재고 0에서 cart 추가 허용**: UX는 좋지만 결제 실패 폭주.
## 🧪 검증 / 중복
- Verified (Shopify Engineering, "Building Resilient Payment Systems", 2024; AWS retail patterns).
- 신뢰도 A.
## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — reservation 모델·Lua·sharding 추가 |