Files
2nd/10_Wiki/Topic_Programming/Coding/DB_Change_Data_Capture.md
T
Antigravity Agent 9148c358d0 docs(10_Wiki): 위키 전체 재구성 — Topic_* 폴더를 4개 카테고리로 통합 + 대규모 중복 제거
Topic_Agent/Topic_Blog/Topics/Topics_Biz/Topics_Meeting/Topics_Rag의 마크다운 지식 문서를
Topic_General/Topic_Programming/Topic_Graphic/Topic_Business 4개 카테고리로 재분류.

- 중복 제거: frontmatter의 status:duplicate/merged + duplicate_of/redirect_to 필드로
  자기 자신을 중복으로 선언한 리다이렉트 stub 1032개 제거, 완전 동일 내용 파일 472개 제거,
  동일 파일명·다른 내용 충돌 시 더 큰(완전한) 버전만 유지(162개 제거) — 총 1639개 중복 제거.
- 분류: 폴더 단위로 명확한 항목(AI_and_ML/Coding/Architecture 등 → Programming,
  Comfyui/Visual_Effects → Graphic, Topics_Biz/Topics_Meeting/사업 등 → Business,
  Poetic_Blog_Writing/창의성/Game_Design 등 → General)은 폴더 우선순위로,
  나머지 혼재 폴더(Topic_Agent/Topic_Blog/Topics 루트/Thinking & Reasoning/Other/UI_UX_Assets)는
  title/tags 키워드 스코어링으로 파일 단위 분류(불명확한 경우 General로 폴백).
  원본 폴더명은 "From_*" 서브폴더로 보존해 추적 가능성 유지.
- 최종 배치: Programming 2784 / General 1608 / Graphic 285 / Business 249 = 4926개 문서.
- 에이전트 운영 상태(.astra/.agent/.obsidian/sessions/memory/_company/docs/lessons/_shared/src)는
  지식 콘텐츠가 아니므로 재분류 대상에서 제외하고 원위치 유지.
- Topics/Topic_email(상위 보호 폴더 Topic_email과 파일명 100% 중복) 삭제 — 보호 폴더 자체는 미변경.
- 완전히 비게 된 Topic_Agent/Topic_Blog/Topics_Biz/Topics_Rag 폴더 제거.
2026-07-05 00:33:48 +09:00

4.7 KiB

id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
id title category status source_trust_level verification_status created_at updated_at tags tech_stack applied_in aliases
db-change-data-capture CDC — Debezium / WAL / 실시간 동기화 Coding draft B conceptual 2026-05-09 2026-05-09
database
cdc
debezium
vibe-coding
language applicable_to
Postgres / Debezium / Kafka
Backend
CDC
Debezium
logical replication
WAL
binlog
outbox alternative

Change Data Capture

DB 변경을 실시간 stream 으로. Postgres logical replication / MySQL binlog → Debezium → Kafka. Outbox 패턴의 외부 + 무관 시스템 동기화에 강력. 앱 변경 X.

📖 핵심 개념

  • WAL (Postgres) / binlog (MySQL): DB 가 commit 한 모든 변경을 시간 순으로 기록.
  • Logical replication: WAL 을 row-level 변경으로 디코드.
  • CDC tool: Debezium / wal2json / pgcapsule / Materialize.
  • Use case: 검색 인덱스 / cache 갱신 / 마이크로서비스 동기화 / 분석 DB.

💻 코드 패턴

Postgres logical replication 활성화

-- postgresql.conf
wal_level = logical
max_replication_slots = 5
max_wal_senders = 5

-- publication 생성
CREATE PUBLICATION app_pub FOR TABLE orders, users;

-- replication slot
SELECT pg_create_logical_replication_slot('debezium', 'pgoutput');

Debezium config (Postgres → Kafka)

{
  "name": "orders-connector",
  "config": {
    "connector.class": "io.debezium.connector.postgresql.PostgresConnector",
    "database.hostname": "pg",
    "database.user": "debezium",
    "database.dbname": "app",
    "topic.prefix": "app",
    "plugin.name": "pgoutput",
    "publication.name": "app_pub",
    "slot.name": "debezium",
    "table.include.list": "public.orders,public.users"
  }
}

자동 생성: app.public.orders, app.public.users Kafka topic.

CDC 메시지 형식

{
  "before": { "id": 1, "status": "open", ...},
  "after":  { "id": 1, "status": "shipped", ...},
  "op": "u",            // c=create, u=update, d=delete
  "ts_ms": 1234567890,
  "source": {...}
}

Consumer (검색 인덱스 동기)

const consumer = kafka.consumer({ groupId: 'es-indexer' });
await consumer.subscribe({ topic: 'app.public.orders' });

await consumer.run({
  eachMessage: async ({ message }) => {
    const e = JSON.parse(message.value!.toString());
    switch (e.op) {
      case 'c': case 'u':
        await es.index({ index: 'orders', id: e.after.id, body: e.after });
        break;
      case 'd':
        await es.delete({ index: 'orders', id: e.before.id });
        break;
    }
  },
});

Snapshot (초기 동기화)

  • Debezium 시작 시 초기 SELECT * → CDC stream 으로.
  • snapshot.mode: initial / when_needed / never.

Outbox via CDC (Debezium EventRouter)

-- outbox 테이블 (위 Outbox 패턴)
INSERT INTO outbox (aggregate_type, aggregate_id, event_type, payload) VALUES (...);
"transforms": "outbox",
"transforms.outbox.type": "io.debezium.transforms.outbox.EventRouter",
"transforms.outbox.route.by.field": "aggregate_type",
"transforms.outbox.route.topic.replacement": "events.${routedByValue}"

→ 자동으로 events.order topic 등으로 라우팅.

Schema evolution

ADD COLUMN: 자동 호환
DROP COLUMN: consumer 가 안 쓰면 OK
RENAME: 보통 깨짐 — schema registry 호환 정책

Lag 모니터링

-- replication slot lag
SELECT slot_name, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS lag
FROM pg_replication_slots;

알람: lag > 1GB.

Retention

-- 안 쓰는 slot = WAL 무한 누적
SELECT pg_drop_replication_slot('unused');

🤔 의사결정 기준

동기화 대상 추천
Search (Elasticsearch) CDC → Kafka → indexer
Cache (Redis) CDC + invalidation
분석 DW (Snowflake/BQ) CDC → Fivetran / Airbyte
마이크로서비스 read model CDC outbox pattern
단순 동기화 App-level event
복잡 변환 Materialize / Flink

안티패턴

  • Slot drop 안 함: WAL 무한 — 디스크 채움.
  • 모든 테이블 CDC: 불필요 트래픽. include.list.
  • Schema 변경 무사고 가정: 신중 + 테스트.
  • Consumer 못 따라감: lag 무한. parallelism / 처리 빠르게.
  • Snapshot 트랜잭션 큰 테이블: 메모리 / 시간. parallelism + chunked.
  • CDC 만 + 앱 이벤트 무시: app intent 와 row 변경이 다름 (UPDATE 시 의미 추측).
  • Replica 에서 CDC: lag 위험. primary 권장.

🤖 LLM 활용 힌트

  • Debezium + Kafka + outbox EventRouter 조합.
  • App 변경 0 + 무관 시스템 동기화.
  • Slot lag / retention 모니터링.

🔗 관련 문서