이 도메인의 학습 목표

이 도메인이 묻는 것

Fundamentals는 2장 아키텍처, 7장 스토리지·리텐션·컴팩션, 8장 스키마와 직렬화의 범위입니다. 개발자 관점의 "이 데이터가 어떻게 저장되고 언제 사라지는가"가 핵심입니다. 브로커를 직접 운영하는 절차(파티션 재할당, 롤링 업그레이드 등)는 CCAAK 쪽 비중이 크지만, CLI 워크플로의 순서는 CCDAK에서도 list order 유형으로 나올 수 있습니다.

핵심 개념 (1) 파티션과 복제

순서 보장의 단위는 파티션입니다

토픽은 여러 파티션으로 나뉘고, 각 파티션은 append-only 로그입니다. 오프셋은 파티션 안에서만 의미가 있고, 토픽 전역 오프셋은 존재하지 않습니다. 같은 키를 가진 레코드는 같은 파티션으로 가므로, 순서를 보장하려면 키를 지정해야 합니다.

파티션 수는 늘릴 수만 있고 줄일 수 없습니다. 그리고 늘리면 murmur2(key) % numPartitions의 분모가 바뀌므로 기존 키의 파티션 배치가 달라져 순서 보장이 깨집니다. 또한 파티션 수 증가는 그 토픽을 구독하는 컨슈머 그룹의 리밸런스를 유발합니다.

ISR과 내구성 계산

각 파티션에는 리더 하나와 팔로워가 있고, 리더를 충분히 따라잡은 레플리카의 집합을 ISR(In-Sync Replicas)이라고 합니다. 팔로워가 replica.lag.time.max.ms(브로커 기본 30000) 동안 리더를 따라잡지 못하면 ISR에서 빠집니다.

acks=all은 "모든 레플리카"가 아니라 "현재 ISR의 모든 멤버"의 응답을 기다립니다. 그래서 ISR이 1로 줄어든 상태에서는 acks=all도 사실상 acks=1이 됩니다. 이 구멍을 막는 것이 min.insync.replicas입니다.

RF=3에서 min.insync.replicas별 내구성 (모두 acks=all 전제)
min.insync.replicas 쓰기 가능한 최대 장애 브로커 수 특징
1 (기본값) 2대 가용성 최대. 리더만 살아 있으면 쓰기 성공 → 리더가 죽으면 유실 가능
2 (권장) 1대 가용성과 내구성의 균형. 프로덕션 표준 조합
3 0대 내구성 최대. 한 대만 죽어도 쓰기가 멈춤

오프셋 4종

하나의 파티션 로그 위에 동시에 존재하는 네 지점
이름의미누가 정하는가
log-start-offset리텐션으로 삭제된 경계. 이보다 앞은 존재하지 않음브로커 (리텐션)
committed offset컨슈머 그룹이 "여기까지 처리했다"고 커밋한 위치컨슈머 그룹
high watermarkISR 전원이 복제를 마친 상한. 컨슈머는 이 이상 읽지 못함리더 (ISR 최소 LEO)
LEO (log end offset)리더가 기록한 마지막 다음 위치리더

인터랙티브 그림으로 네 지점이 어떻게 벌어지는지 보려면 1장 오프셋 절2장을 보세요. consumer lag = high watermark − committed offset이며, LEO에서 빼는 것이 아닙니다. 이 정의는 Observability 도메인에서도 다시 나옵니다.

핵심 개념 (2) 메시지 크기 — 5개 설정이 정합해야 합니다

이 도메인에서 가장 자주 나오는 matching 문항이 "설정 ↔ 소속"입니다. 메시지 크기 관련 설정은 다섯 개이고, 각각 다른 컴포넌트에 있습니다. 하나만 올리면 다른 곳에서 막힙니다.

메시지 크기 관련 5개 설정 (Apache Kafka 4.3 기본값)
설정 소속 기본값 막히면 나타나는 증상
max.request.size 프로듀서 1048576 클라이언트에서 즉시 RecordTooLargeException (브로커까지 가지 않음)
message.max.bytes 브로커 1048588 브로커가 거부. 프로듀서는 재시도 후 실패
max.message.bytes 토픽 1048588 브로커 기본값을 토픽 단위로 오버라이드. 이 값이 실제 판정 기준
max.partition.fetch.bytes 컨슈머 1048576 파티션당 상한. 큰 레코드가 이보다 크면 진행이 멈출 수 있음
fetch.max.bytes 컨슈머 52428800 요청 전체 상한 (50MB)
replica.fetch.max.bytes 브로커 (팔로워) 1048576 팔로워가 큰 레코드를 못 복제 → ISR 축소. 가장 늦게 발견되는 지점

핵심 개념 (3) 리텐션과 컴팩션

cleanup.policy 두 값의 동작
관점delete (기본값)compact
기준시간(retention.ms) 또는 크기(retention.bytes)키별 최신 값만 유지
삭제 단위세그먼트 전체키 단위로 옛 값 제거
키 필요불필요필수 — 키가 없으면 컴팩션이 동작하지 않습니다
용도이벤트 스트림, 로그상태(state) 토픽, changelog, __consumer_offsets
삭제 표현기간 경과tombstone — value가 null인 레코드
리텐션·컴팩션 관련 토픽 설정 (Apache Kafka 4.3 기본값)
설정기본값시험 포인트
cleanup.policydeletecompact,delete 조합도 가능
retention.ms604800000 (7일)-1이면 시간 기준 삭제를 하지 않음
retention.bytes-1 (무제한)파티션당 크기입니다. 토픽 전체가 아닙니다
segment.bytes1073741824 (1GiB)삭제가 세그먼트 단위이므로 실제 보관량을 좌우
segment.ms604800000 (7일)세그먼트를 시간으로 마감. 이게 크면 리텐션이 늦게 적용됨
min.cleanable.dirty.ratio0.5더러운 비율이 이 값을 넘어야 컴팩션 시작
delete.retention.ms86400000 (1일)tombstone을 유지하는 기간. 이 뒤에 tombstone도 사라짐
min.compaction.lag.ms0레코드가 최소 이 시간은 컴팩션 대상이 되지 않음
max.compaction.lag.ms9223372036854775807사실상 무제한. 컴팩션 지연 상한을 강제할 때 낮춤
message.timestamp.typeCreateTimeLogAppendTime으로 바꾸면 리텐션 기준 시각이 달라짐

디스크 용량 산정

필요 용량 개산식
필요 디스크 = 일일 유입량 × 보관 일수 × 복제 계수 × (1 − 압축률) × 여유 계수

예) 200GB/일, 7일 보관, RF=3, 압축률 60%, 여유 30%
  = 200 × 7 × 3 × 0.4 × 1.3
  = 2184 GB  → 브로커 3대면 대당 약 730GB

계산 문항으로 나올 수 있습니다. 복제 계수를 곱하는 것을 잊지 않는 것이 핵심이고, 압축은 프로듀서가 압축한 배치를 브로커가 그대로 저장하므로 (토픽 compression.type=producer가 기본값) 디스크에서도 압축 효과가 유지됩니다.

핵심 개념 (4) 스키마 호환성과 배포 순서

Schema Registry는 Apache Kafka 본체가 아니라 Confluent 컴포넌트이지만 CCDAK 출제 범위입니다. 이 절의 두 표가 이 도메인 최고의 가성비 산출물입니다.

변경 유형 × 호환성 모드 — 허용 여부
스키마 변경 BACKWARD FORWARD FULL NONE
default 있는 필드 추가 허용 허용 허용 허용
default 없는 필드 추가 거부 허용 거부 허용
default 있는 필드 삭제 허용 허용 허용 허용
default 없는 필드 삭제 허용 거부 거부 허용
필드 타입 변경 거부
(승격 가능한 조합 제외)
거부 거부 허용
필드 이름 변경 위험
(alias 필요)
위험 위험 허용
호환성 모드별 배포 순서 — 이 표를 외우면 관련 문항을 전부 잡습니다
모드 의미 먼저 배포할 쪽 비교 대상
BACKWARD
(기본값)
새 스키마로 옛 데이터를 읽을 수 있다 컨슈머 먼저 직전 버전
BACKWARD_TRANSITIVE 같음 컨슈머 먼저 모든 이전 버전
FORWARD 옛 스키마로 새 데이터를 읽을 수 있다 프로듀서 먼저 직전 버전
FORWARD_TRANSITIVE 같음 프로듀서 먼저 모든 이전 버전
FULL 양방향 순서 무관 직전 버전
FULL_TRANSITIVE 양방향 순서 무관 모든 이전 버전
NONE 검사하지 않음

wire format과 subject 전략

Schema Registry가 붙이는 바이트 레이아웃
[0x00]  [4바이트 schema id]  [Avro/Protobuf 페이로드]
  1B          4B                  나머지
  ↑           ↑
magic byte   빅엔디안 정수. 컨슈머는 이 id 로 레지스트리에서 스키마를 조회

핵심 개념 (5) 보안 프로토콜과 관리 CLI

security.protocol 4종

클라이언트 security.protocol 값과 의미
인증 전송 암호화 비고
PLAINTEXT없음없음개발용만
SSL선택적 (mTLS 시)TLS클라이언트 인증서로 인증도 가능
SASL_PLAINTEXTSASL없음자격증명이 평문으로 흐릅니다
SASL_SSLSASLTLS프로덕션 권장

파티션 재할당 워크플로

kafka-reassign-partitions.sh 3단계 (list order 유형 단골)
# 1) 계획 생성 — 현재 배치와 제안 배치를 JSON 으로 출력한다
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --topics-to-move-json-file topics.json \
  --broker-list "1,2,3" --generate

# 2) 실행 — 복제 대역폭을 제한해 프로덕션 영향을 줄인다
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file plan.json --throttle 50000000 --execute

# 3) 확인 — 완료되면 스로틀이 해제된다. 반드시 verify 까지 해야 한다
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file plan.json --verify

반드시 외워야 할 설정값

Fundamentals 도메인 필수 암기 설정 (Apache Kafka 4.3)
설정소속기본값시험 포인트
num.partitions브로커1자동 생성 토픽의 파티션 수. 소비 병렬성의 상한
default.replication.factor브로커1자동 생성 토픽은 복제되지 않습니다
auto.create.topics.enable브로커true오타 토픽이 조용히 생성됨
min.insync.replicas브로커 · 토픽1acks=all과만 상호작용
unclean.leader.election.enable브로커 · 토픽falsetrue면 가용성↑ 내구성↓ (유실 허용)
replica.lag.time.max.ms브로커30000이 시간 못 따라오면 ISR 제외
message.max.bytes브로커1048588압축 후 배치 기준
replica.fetch.max.bytes브로커1048576하드 상한 아님 · 빼먹으면 복제 처리량 급감
offsets.retention.minutes브로커10080 (7일)커밋 오프셋 만료 → auto.offset.reset 발동
transaction.state.log.replication.factor브로커3EOS는 브로커 3대 이상을 전제
transaction.state.log.min.isr브로커2단일 브로커 개발 환경에서 낮춰야 EOS가 동작
cleanup.policy토픽deletecompact, compact,delete
retention.ms토픽6048000007일
segment.bytes토픽10737418241GiB. 삭제 단위
delete.retention.ms토픽86400000tombstone 수명 1일
min.cleanable.dirty.ratio토픽0.5컴팩션 시작 조건
compression.type토픽producer프로듀서 기본값(none)과 다릅니다
remote.storage.enable토픽falseTiered Storage 사용 여부

자주 나오는 함정

함정 1 — 리텐션 vs 컴팩션

"오래된 데이터를 없앤다"는 점만 같습니다
관점리텐션 (delete)컴팩션 (compact)
무엇이 남는가기간 안의 모든 레코드키별 최신 값 하나
어디 설정토픽 (브로커 기본값 있음)토픽
언제 발동세그먼트가 마감되고 기간·크기 초과 시dirty ratio 초과 시 백그라운드 클리너
혼동 시 결과상태 토픽에 delete가 남아 상태가 사라짐이벤트 토픽에 compact를 걸어 이력이 사라짐
출제 형태"키별 최신 상태만 필요한 토픽의 설정은?" / "컴팩션 토픽에서 옛 값이 아직 보이는 이유는?"

함정 2 — high watermark vs LEO vs committed offset

세 지점을 섞으면 lag 계산 문항이 전부 틀립니다
관점committed offsethigh watermarkLEO
주인컨슈머 그룹파티션 리더 (ISR 기준)파티션 리더
저장 위치__consumer_offsets브로커 메모리·복제 상태로그의 끝
컨슈머가 읽는 상한이것읽을 수 없음
lag 계산lag = high watermark − committed offset
출제 형태"컨슈머가 아직 못 본 레코드 수는?" — LEO로 계산한 선택지가 함정

함정 3 — TRANSITIVE vs 비-TRANSITIVE

차이는 "비교 대상"뿐입니다
관점BACKWARDBACKWARD_TRANSITIVE
비교 대상직전 버전만등록된 모든 이전 버전
누적 변경v1↔v3 호환이 깨질 수 있음깨지지 않음
과거 데이터 재처리오래된 데이터를 새 스키마로 읽다 실패 가능안전
출제 형태"v1 데이터를 v3 컨슈머로 재처리하려면 어떤 모드가 필요한가"

함정 4 — retention.ms vs segment.ms

보관 기간을 짧게 줬는데 데이터가 안 사라지는 이유
관점retention.mssegment.ms
기본값604800000 (7일)604800000 (7일)
의미얼마나 보관할지세그먼트를 얼마 만에 마감할지
관계삭제는 마감된 세그먼트 단위로만 일어납니다. 활성 세그먼트는 지워지지 않습니다
혼동 시 결과retention.ms=3600000(1시간)으로 줘도 segment.ms가 7일이면 최대 7일치가 남습니다
출제 형태"보관 기간을 줄였는데 디스크가 안 줄어드는 이유는?"

함정 5 — delete.retention.ms vs retention.ms

둘 다 "retention"이 붙지만 대상이 다릅니다
관점retention.msdelete.retention.ms
대상일반 레코드tombstone(value=null)
기본값604800000 (7일)86400000 (1일)
정책cleanup.policy=deletecleanup.policy=compact
혼동 시 결과tombstone이 너무 빨리 사라지면, 오래 멈췄던 컨슈머가 삭제 사실을 못 보고 옛 값을 유지합니다
출제 형태"컴팩션 토픽에서 삭제가 하위 시스템에 전파되지 않은 이유는?"

함정 6 — 크기 설정 3종의 소속

이름이 비슷해 소속을 바꿔 놓는 선택지가 많습니다
관점max.request.sizemessage.max.bytesfetch.max.bytes
소속프로듀서브로커 (토픽은 max.message.bytes)컨슈머
기본값1048576104858852428800
언제 발동전송 직전 클라이언트에서브로커가 배치를 받을 때fetch 응답 크기 산정 시
초과 시RecordTooLargeException (즉시)브로커가 거부(상한이므로 초과 없음)
출제 형태"1.5MB 메시지를 보내려면 무엇을 바꿔야 하는가 (모두 고르시오)"

코드·설정 읽기 문제 대비

스니펫 1 — 이 토픽 설정의 문제

kafka-topics.sh 로 만든 상태 토픽
bin/kafka-topics.sh --create --topic user-profile-state \
  --bootstrap-server localhost:9092 \
  --partitions 6 --replication-factor 3 \
  --config retention.ms=86400000

스니펫 2 — 이 스키마 변경은 통과하는가

v1 → v2 (subject 호환성 모드는 BACKWARD)
// v1
{ "type": "record", "name": "Order", "fields": [
    { "name": "orderId", "type": "string" },
    { "name": "amount",  "type": "long" } ]}

// v2 — couponCode 를 추가
{ "type": "record", "name": "Order", "fields": [
    { "name": "orderId",    "type": "string" },
    { "name": "amount",     "type": "long" },
    { "name": "couponCode", "type": "string" } ]}

스니펫 3 — 이 계산의 답

파티션 상태
Topic: payments  Partition: 3
  Leader: 2   Replicas: 2,3,1   Isr: 2,3
  log-start-offset: 1200
  committed offset (group=billing): 8400
  high watermark: 9100
  LEO: 9350

도메인 미니 퀴즈

공식 문서 출처