본 포스팅은 인프런 데브원영님의 [아파치 카프카 애플리케이션 프로그래밍]의 강의를 수강 후 정리하는 글입니다.
1. 복제
1-1. 브로커의 역할 - 복제(Replication)
복제는 카프카를 Fault Tolerant System으로 동작할 수 있게 하는 근본 원동력
브로커 중 일부에 장애가 생기더라도 데이터를 유실하지 않음
카프카의 데이터 복제는 파티션 단위로 이루어짐
파티션의 복제 개수(Replication Factor) 설정이 가능한데, 설정을 하지 않는다면 브로커에 설정된 옵션 값 따라감
복제된 파티션은 리더와 팔로워로 구성됨
- 리더: 프로듀서 또는 컨슈머와 직접 통신하는 파티션
- 팔로워: 나머지 복제 데이터를 가지고 있는 파티션
복제하는 과정: 팔로워들은 리더의 오프셋을 확인하여, 자신의 오프셋과 차이가 나는 경우 리더로부터 데이터를 가져와서 자신의 데이터에 저장
장점: 복제를 통해 데이터를 안전하게 사용
단점: 복제 개수만큼 저장 용량이 증가
1-2. 브로커에 장애가 발생한 경우
브로커가 다운이 되면, 해당 브로커에 있는 리더 파티션은 사용 불가되어 팔로워 중 하나가 리더의 지위를 넘겨받음
2. ISR
2-1. ISR(in-Sync-Replicas)
ISR: 리더와 팔로워가 모두 싱크가 된 상태
리더의 데이터를 모두 복제하지 못한 상태가 리더로 선출되면 데이터 유실 가능
- unclean.leader.election.enable=true
유실을 감수함
복제가 안된 팔로워를 리더로 승급
- unclean.leader.election.enable=false
유실을 감수하지 않음
브로커가 복구될 때까지 중단
3. 토픽과 파티션
3-1. 토픽과 파티션은 무엇인가
토픽: 카프카에서 데이터를 구분하기 위해 사용하는 단위
파티션: 자료구조에서 접하는 큐(queue)와 비슷한 구조
레코드: 프로듀서가 보낸 데이터
3-2. 토픽 생성 시 파티션이 배치되는 방법
리더들이 라운드 로빈 방식으로 생성된다.
특정 브로커와 통신이 집중되는 hot spot 현상을 막음
linear scale out을 하여 데이터가 많아지더라도 자연스럽게 대응 가능
3-3. 특정 브로커에 파티션이 쏠린 현상
특정 브로커에 파티션이 몰리는 경우, kafka-reassign-partitions.sh 명령을 통해 파티션을 재분배 가능
3-4. 파티션 개수와 컨슈머 개수의 처리량
기본적으로 파티션과 컨슈머의 관계는 1대1이 이상적
컨슈머에 장애가 발생하면, 다른 컨슈머에 파티션을 할당하여 하나의 컨슈머에 여러 파티션도 가능
컨슈머 개수를 늘리면서 동시에 파티션 개수도 늘리면 처리량이 증가
3-5. 파티션 개수
카프카에서 파티션 개수를 줄일 수 없다. 그래서 늘리는 작업을 할 때는 신중히
카프카에서는 파티션의 데이터를 세그먼트로 저장하고, 만에 삭제를 지원한다면 여러 브로커에 저장되어 있는 데이터를 취합하고 정렬까지 해야해서 클러스터에 큰 영향이 갈 수 밖에 없음
4. 레코드
4-1. 레코드의 구성
레코드는 타임스탬프, 헤더, 메시지 키, 메시지 값, 오프셋으로 구성되어 있음
브로커에 한 번 적재된 레코드는 수정할 수 없고, 로그 리텐션 기간 또는 용량에 따라서만 삭제됨
4-2. 레코드 - 타임스탬프
타임스탬프는 스트림 프로세싱에서 활용하기 위한 시간을 저장하는 용도
카프카 0.10.0.0 이후 버전부터 추가되어 Unix timestamp가 포함
기본 값: Producer Record 생성 시간(Create Time)
브로커 적재 시간(Log Append Time)으로 토픽 단위로 설정 가능
message.timestamp.type 옵션이용
4-3. 레코드 - 오프셋
오프셋을 기반으로 처리가 완료된 데이터와 앞으로 처리해야할 데이터를 구분
프로듀서가 생성한 레코드에 바로 존재하지 않음
레코드가 브로커에 적재될 때 오프셋이 지정
4-3. 레코드 - 헤더
카프카 0.11 버전부터 제공된 기능
key/value 데이터를 추가 가능하며, 레코드의 스키마 버전이나 포맷 등 데이터 프로세싱에 참고할만한 정보
4-4. 레코드 - 메시지 키
메시지 키는 처리하고자 하는 메시지 값의 분류(파티셔닝)를 하기 위한 용도
파티셔닝에 사용하는 메시지 키는 파티셔너에 따라 토픽의 파티션 번호가 정해짐
메시지 키를 지정한 경우: 해쉬값에 의해서 특정 파티션에 매핑되어 전달
메시지 키를 지정하지 않은 경우: null로 설정되어, 특정 토픽의 파티션에 라운드 로빈으로 전달됨
4-3. 레코드 - 메시지 값
실질적으로 처리할 데이터가 담기는 공간
Float, Byte[], String 등 다양한 형태로 지정 가능하며 필요에 따라 사용자 지정 포맷으로 직렬화/역직렬화 클래스 만들어 사용 가능
브로커에 저장된 레코드의 메시지 값은 어떤 포맷으로 직렬화되어 저장되었는지 모르기 때문에 컨슈머는 미리 역직렬화 포맷을 알고 있어야 함
5. 유지보수하기 좋은 토픽 이름 정하기
5-1. 토픽 이름 제약 조건
- 빈 문자열 x
- 마침표 하나 또는 마침표 둘로 생성 x
- 294자 미만으로 생성
- 영어 대소문자, 숫자 0~9, 마침표(.), 언더바(_), 하이픈(-) 조합으로 생성 가능
- 카프카 내부 로직 관리 목적으로 사용되는 2개의 토픽(__consumer_offsets, __transaction_state)과 동일한 이름 불가
- 카프카 내부적으로 토픽 이름에 마침표(.)와 언더바(_)가 동시에 들어가면 이슈가 발생할 수 있음
5-2. 의미 있는 토픽 이름 작명 방법
토픽 이름은 데이터의 얼굴
토픽 이름 변경이 불가
이름 변경하기 위해서는 삭제 후 다시 생성
다소 까다롭더라도 카프카 클러스터 사용자에게 토픽 생성에 대한 규칙을 인지시키고 규칙에 따르도록 해야함
5-3. 토픽 작명의 템플릿과 예시
<환경>.<팀명>.<애플리케이션명>.<메시지타입>
ex) prd.marketing-team.sms-platform.json
<프로젝트명>.<서비스명>.<환경>.<이벤트명>
ex) commerce.payment.prd.notification
<환경>.<서비스명>,<JIRA번호>.<메시지타입>
ex) dev.email-sender.jira-1234.email-vo-custom
<카프카-클러스터명>.<환경>.<서비스명>.<메시지타입>
ex) aws-kafka.live.marketing-platform.json
★메시지타입을 넣으면 좋은 이유★
토픽에 프로듀서에서 레코드를 넣을 때 직렬화를 하게 되는데, 컨슈머는 어떻게 직렬화되었는지 알아야함
어떤 포맷인지 적는 것이 좋음
6. 클라이언트 메타데이터와 브로커 통신
6-1. 클라이언트 메타데이터
메타데이터에는 클라이언트가 어떤 브로커와 통신해야하는지 알 수 있는 정보가 들어있음
카프카 프로듀서 메타데이터 옵션
metadata.max.age.ms: 메타데이터를 강제로 리프레시하는 간격(디폴트: 5분)
metadata.max.idle.ms: 프로듀서가 유휴상태일 경우 메타데이터를 캐시에 유지하는 기간(디폴트: 5분)
6-2. 클라이언트 메타데이터가 이슈가 발생한 경우
카프카 클라이언트는 반드시 리더 파티션과 통신을 해야함
리프래시되지 않은 상태에서 잘못된 브로커로 데이터를 요청하면 LEADER_NOT_AVAILABLE exception 발생
이 에러가 자주 발생한다면 메타데이터 리프래시 간격을 확인해야함
'Kafka' 카테고리의 다른 글
[Apache Kafka] 4. 아파치 카프카 CLI 활용(1) - 브로커, 주키퍼 생성 (3) | 2024.10.10 |
---|---|
[Apache Kafka] 3. 카프카 클러스터 운영 (0) | 2024.10.09 |
[Apache Kafka] 2. 카프카 기본 개념 설명(1) (1) | 2024.10.01 |
[Apache Kafka] 1. 아파치 카프카의 역사와 미래 (0) | 2024.09.30 |
Kafka - PostgreSQL to MariaDB (2) (0) | 2024.06.30 |