콘텐츠로 이동
Study NoteKafka

7. 토픽 설계

코드는 언제든 고치지만, 파티션 수와 키는 데이터가 쌓인 뒤엔 못 무른다

이 장에서 처음 나오는 말4개
보존Retention
데이터를 언제까지 남길지의 정책. 기간(retention.ms)과 용량(retention.bytes)으로 정하고, 지나면 세그먼트째 지운다.
컴팩션Compaction
기간이 아니라 키별 최신값만 남기는 보존 방식. "이력"이 아니라 "현재 상태"가 필요한 토픽에 쓴다.
툼스톤Tombstone
value가 null인 레코드. 컴팩션 토픽에서 "이 키를 지워라"는 표시다.
스키마Schema
토픽에 흐르는 메시지의 형식 계약. 생산자와 소비자가 독립 배포되는 순간부터 필요해진다.

토픽은 이벤트 종류 하나 = 토픽 하나가 기본형이다. 판단 기준은 스키마다 — 한 토픽에는 한 가지 형식의 메시지가 흐르는 것이 소비자를 단순하게 만든다.

  • 이름은 규칙을 세워 일관되게 — <도메인>.<대상>.<사건> 꼴이 흔하다 (order.payment.completed, user.account.created). 나중에 ACL·정리의 단위가 된다
  • 너무 잘게 (사건마다 새 토픽 수백 개) — 관리·모니터링이 흩어진다. 너무 굵게 (만능 events 토픽 하나) — 소비자가 필요 없는 메시지까지 다 받아 거른다. 도메인 단위로 묶고, 소비 패턴이 다르면 나눈다 — “같이 읽히는 것끼리 한 토픽”
  • 한 대상의 사건들 사이에 순서가 필요하면 한 토픽이어야 한다 — 토픽이 다르면 같은 키라도 순서가 없다 (6장)

파티션 수 — 가장 무르기 어려운 결정

섹션 제목: “파티션 수 — 가장 무르기 어려운 결정”

2장·5장의 결론이 여기로 모인다 — 파티션 수 = 소비 병렬성의 상한이고, 늘리면 키 배정이 바뀌며, 줄일 수는 없다.

목표 처리량과 컨슈머 하나의 실측 처리량으로 필요한 파티션 수를 구하고 성장 여유를 더하는 계산
  • 병목은 대부분 브로커가 아니라 컨슈머의 처리 속도다(DB 쓰기, API 호출…) — 그래서 분모는 추정이 아니라 실측이어야 한다
  • 감이 없으면 6~12개로 시작하는 것이 무난하다 — 웬만한 서비스 이벤트 토픽에 충분하고, 컨슈머를 늘릴 여유도 있다
  • 많다고 좋은 것이 아니다 — 파티션마다 파일 핸들 · 복제 트래픽 · 리더 선출 부담이 붙는다. “일단 100개”는 클러스터 전체(수천 파티션 규모)에 비용으로 돌아온다

보존 — 지우는 정책이 곧 계약이다

섹션 제목: “보존 — 지우는 정책이 곧 계약이다”

cleanup.policy=delete. 기본 7일(retention.ms) — 대부분의 이벤트 토픽은 이대로 쓴다.

  • 보존 기간은 재처리·복구의 여유 시간이다: “컨슈머가 최대 얼마나 밀려도 되는가” + “며칠 전 데이터까지 재처리할 일이 있는가”로 정한다 (6장의 마지막 사슬)
  • 디스크 계획이 바로 나온다 — 필요 용량 ≈ 유입 속도 × 보존 기간 × RF. 하루 50GB 유입 · 7일 · RF=3 ≈ 1TB가 조금 넘는다. 온프렘에서는 이 식이 곧 장비 계획이다(9장)
  • retention.bytes(파티션당 용량 상한)를 함께 걸면 디스크 만석 사고의 안전판이 된다

스키마 — 형식 계약을 어떻게 지킬 것인가

섹션 제목: “스키마 — 형식 계약을 어떻게 지킬 것인가”

브로커는 value를 검사하지 않는다(2장) — 형식이 깨진 메시지도 그대로 들어간다. 생산자와 소비자가 따로 배포되는 순간, “필드 하나 바꿨더니 소비자가 죽었다”는 사고는 시간 문제다.

  • 시작은 JSON으로 충분하다 — 대신 버전 필드를 넣고, 소비자는 모르는 필드를 무시하게(관용적 읽기) 짠다
  • 토픽·연동이 늘면 스키마 레지스트리(8장)로 계약을 강제한다 — 호환성 규칙(뒤 호환: 필드 추가는 되고 삭제·타입 변경은 막는 식)을 등록 시점에 검사해, 깨지는 변경이 배포 전에 걸린다
  • 어느 쪽이든 원칙은 같다 — 스키마 변경은 추가만, 삭제·의미 변경은 새 토픽
  • 토픽은 이벤트 종류 단위 · 한 토픽 한 스키마 · 순서가 필요한 사건들은 한 토픽에
  • 파티션 수는 목표 처리량 ÷ 컨슈머 실측 처리량 + 여유 — 감이 없으면 6~12로 시작, 늘리기엔 대가(키 재배정)
  • 보존은 계약이다 — delete는 재처리 여유 시간, compact는 키별 최신 상태. 디스크 = 유입 × 보존 × RF
  • 형식 계약은 처음엔 관용적 JSON, 규모가 붙으면 스키마 레지스트리로 강제(8장)