브로커, 주키퍼
브로커
- 카프카 클라이언트와 데이터를 주고받기 위해 사용하는 주체
- 데이터를 분산저장하여 장애가 발생하더라도, 안전하게 사용할수 있도록 해줌
- 1개의 서버에, 1개의 카프카 브로커 프로세스가 실행된다
- 데이터를 안전하게 처리하기위해, 3대이상의 브로커 서버를 1개의 클러스터로 묶어서 사용
주키퍼
- 카프카 클러스터를 실행하기 위해서 주키퍼를 사용
- 카프카 클러스터 갯수에 맞춰서, 주키퍼도 갯수를 맞춤
- 주키퍼의 root znode에, 카프카클러스터별 znode를 만들고
카프카 클러스터 실행시 주키퍼의root가 아닌, 클러스터별znode로 설정해서 실행
브로커 역할
- 컨트롤러
- 카프카 클러스터의 다수브로커 중 한대가 컨트롤러 역할을한다.
컨트롤러는 다른브로커들의 상태를 체크하고, 브로커가 클러스터에서 빠지면 리더파티션을 재분배한다. - 데이터 삭제데이터 삭제는 파일단위로 이루어지는데 이때단위를(로그 세그먼트, log segment)라고 하고
특정 시점의 스냅샷같은 데이터가 들어가있기때문에, 특정데이터를 선택해서 삭제할수없다 - 컨슈머가 데이터를 가져가더라도, 토픽의 데이터는 삭제되지 않는다는 특징이 있다.
- 컨슈머 오프셋 저장
커밋 : Consumer가 ‘어떤 파티션의 어느 레코드까지 가져갔는지 확인하는 과정'
커밋한 오프셋은 __consumer_offsets
토픽에 저장하고.
저장된 오프셋을 확인한다음, 컨슈머는 다음 레코드를 가져간다
- 컨슈머는 데이터를 메세지큐에서 가져갈때 offset을 commit 을 한다.
- 그룹 코디네이터
- 사용중인 컨슈머가, 컨슈머그룹에서 빠지게되는 경우에 작동
매칭되지않은 파티션을 정상동작하는 컨슈머로 재할당 해준다 (리밸런스과정) - 데이터 저장
config/server.properties
→log.dir
옵션- index파일
- log파일
- timeindex 파일
- checkpoint 파일
- 카프카는 데이터를 FileSystem에 저장한다고 했다
Filesystem의 어느부분에 저장할지를 결정하는데, 일반적으로 토픽이름과 파티션 번호조합으로 활용한다
로그, 세그먼트
로그(log) : offset의 번호가 저장되어 있음. 파일명이 시작오프셋
세그먼트(segment) : 데이터를 가져가는 단위
log.sement.bytes
[log.roll.ms](http://log.roll.ms)
active 세그먼트
가장 최신의 세그먼트(현재 쓰기과정이 일어나고 있는 파일),
Kafka는 ‘데이터를 선택'해서 제거하는것은 불가능하다.
유일한 데이터 제거 방법은 retention 옵션을 설정해서 제거하는 방식만 사용되는데
이때 현재 파일 쓰기를 하고있는 active segment는 완전히 제외하고,
나머지 예전 세그먼트파일(.log) 들을 대상으로 진행된다
[retention.ms](http://retention.ms)
[log.retention.check.interval.ms](http://log.retention.check.interval.ms)
Cleanup Policy, Retention
retention 은 쌓여만 가는 파일시스템에, 중복되고 오래된 데이터를 없에주는거다
cleanup.policy=delete
카프카에서는 세그먼트단위로 삭제가 발생하기때문에
로그단위(레코드 단위)로 개별삭제는 불가능하다
수정또한 불가능하기때문에
프로듀서, 컨슈머를 사용할때 데이터를 검증하는 방식을 사용한다
Compact : 중복제거
log세그먼트에는 레코드가 3개의 값(offset, key, value) 을 가진상태로 저장된다
cleanup.policy=compact
는 중복상태의 레코드 key 중에
active segment를 제외하고, 가장 최신의 key 를 제외하고, 중복된 key를 제거한다
Tail 영역 : cleanup policy 에 의해 압축이 완료된 레코드들 (중복이없는상태)
Head 영역 : 압축정책이 되기 전 레코드들(중복이 있는 상태)
min.cleanable.dirty.ratio
: tail 영역, head영역의 비율을 설정해서 cleanup-policy 정책을 실행한다
replication : 데이터 복제
데이터를 복제(replication) 를 했을때의 이점 :
클러스터 로 묶인 브로커 중 일부에 장애가 발생하더도
데이터를 복제해놓음으로써 데이터를 유실하지않기 위함이다
데이터의 복제단위 : 파티션
갯수 : replication factor
에 따라 설정된다( 1:복제없음, 갯수는 브로커갯수)
이때 복제된 파티션은 ‘리더파티션', ‘팔로워파티션' 으로 구성되는데
- 이때 [P]와 [C]랑 직접 통신하는 파티션을 ‘리더파티션' 이라고 한다
- 리더파티션을 따라가는 파티션을 ‘팔로워파티션' 이라고 한다.
파티션의 내부에는 데이터가 얼마나 바뀌었는지 offset값이 존재하는데
이때 팔로워파티션은 ‘리더파티션' 의 오프셋 값을 확인하고 replication 진행한다
복제할때의 단점은 복제갯수만큼 저장용량이 증가한다는 것이지만
복제를 통해 데이터를 안전하게 사용할수 있다. 일반적으로 2 이상으로 설정
리더파티션에 장애가 발생한경우
리더파티션은 [P][C]와 직접적으로 통신하고
팔로워파티션은 리더파티션의 오프셋값을 보고 복제한다고 했다
리더파티션에 장애가 발생하면, 장애가 발생한 리더파티션은 더이상 사용할수없기때문에,
팔로워 파티션이 리더파티션의 지위를 넘겨받는다
리더파티션이 없이 작동할수 있냐? 하면 이건 NO다.
원론적으로 [P][C]는 리더파티션하고만 통신을 하기때문이다.
ISR : In Sync Replicas
ISR은 리더파티션과 팔로워파티션이 모두 싱크가 된 상태를 뜻한다
팔로워파티션은 리더파티션의 오프셋값을 확인하고 복제하는데
이때 리더파티션의 값과, 팔로워파티션에서 가져간 값이 일치하는경우를 ISR이라고 한다
unclean.leader.election.enable
만약 ISR상태가 아닌상태에서 장애가 난다면 어떨까?
ISR이 아닌데상태(리더파티션, 팔로워파티션의 오프셋이 다른상태)에서 장애가 난다면
→ 리더파티션 팔로워파티션의 오프셋이 다르다 → 현재 가진 데이터가 다르다 ⇒ 데이터 유실
ISR상태가 아니여도, 팔로워파티션을 리더파티션의 지위를 얻게하는옵션
unclean.leader.election.enable
=true
: 유실을 감수한다. 복제안된 팔로워파티션을 리더로 승급
=false
: 유실감수 안한다. 리더파티션이 복구될때까지 서비스 중단
하이워터마크
리더파티션과 팔로워파티션들은 복제로 인해 서로 가져간 데이터의 갯수가 달라진다.
이로인해 replication lag이 발생한다
[C]는 min.insync.recplias
에 설정된 값 이상으로 복제된 레코드를 가져갈수 있게 된다
컨슈머가 가져갈수 있는 레코드의 오프셋 번호를 하이워터마크라고 한다
0번 : 토픽 - 리더파티션(0, 1, 2, 3)
1번 : 토픽 - 팔로워파티션(0, 1, 2)
2번 : 토픽 - 팔로워파티션(0, 1)
min.insync.replicas = 2 일때
→ 리더파티션을 제외하고 (2-1)개의 토픽에서 최종적으로 sync맞춰진 오프셋번호는 (0,1,2) 이다
⇒ 컨슈머가 가져가는 데이터는 sync된 오프셋번호 (0, 1, 2)
⇒ 이때의 하이워터마크는 마지막오프셋번호인 (2) 이다
레코드
[P]에서 브로커로 데이터를 보낸 상황이면
보내진 데이터는 브로커 내부의 토픽에, 파티션에서 저장된다
이때 [P]는 데이터를 보낼때 메세지키-메세지값 의 형태로 보낸다
파티션에는 프로듀서가 보낸 데이터들이 저장되는데, 이를 레코드 라고 부른다
레코드는FIFO의 형식을 가지고 있고,
먼저 들어간 레코드를 [C]가 순서대로 가져가기때문에 해당 방식이라고 말한다
[C]가 데이터(레코드)를 가져갔다고해서, 브로커내부의 토픽내부의 파티션에서는 가져간데이터(레코드)를 지우지않는데
이때문에 동일한 레코드여도, 다양한 컨슈머 그룹이 토픽의 데이터를 여러번 가져갈수 있다
파티션배치 : Round-Robin
토픽생성시 파티션의 배치방법은 roundrobin 형식 (모두 돌아가면서 가져가는거 )를 사용
5개의 토픽을 3개의 브로커에 배치하는 상황
- 리더파티션 배치
0번 브로커 : 0, 3 (리더:0,3)
1번 브로커 : 1, 4 (리더:1,4)
2번 브로커 : 2 (리더:2)
이런식으로 골고루 분배되어서 만들어진다
라운드로빈방식의 장점은 [P][C]가 리더파티션과 통신할때에
리더파티션들이 많으면 DATA를 하나의 파티션과의 통신하느게아니라
여럽곳에 나눠서 분배하기때문에 서버가 안터질거다
- 팔로워파티션 배치
0번 브로커 : 0, 1, 2, 3, 4 (리더:0,3)(팔로워 : 1,2,4)
1번 브로커 : 0, 1, 2, 3, 4 (리더:1,4) (팔로워 : 0,2,3)
2번 브로커 : 0, 1, 2, 3, 4 (리더:2) (팔로워 : 0,1,3,4)
리더파티션은 팔로워파티션과 통신할거고
이때 파티션의 번호대로 통신을 할텐데
0번 리더파티션 은 0번 팔로워파티션과 통신한다
0번 리더파티션은 0번 브로커에있고, 0번 팔로워파티션은 1번브로커, 2번브로커에 있으므로
0번 브로커의 0번리더파티션은, 1번 브로커의 0번팔로워파티션, 2번 브로커의 0번 팔로워 파티션과 통신한다
파티션 재분배
라운드로빈방식으로 리더파티션을 분배한다고했는데
하나의 브로커에 모든 리더파티션을 몰빵시키면 어떨까?
리더파티션 몰빵 브로커에 트래픽 터져날거다
[kafka-reassign-partitions.sh](http://kafka-reassign-partitions.sh)
로 파티션 재분배 가능
파티션 : 컨슈머 갯수
파티션은 카프카의 병렬처리의 핵심임
1개의 파티션은 무조건 1개의 컨슈머랑 연결되는데
1개의 컨슈머는 n개의 파티션에서 데이터를 받아올수 있다
컨슈머에서 처리하는 데이터양을 늘리고 싶으면
컨슈머만 갯수를 늘리는게아니라,
파티션의 갯수를 먼저늘리고, 컨슈머도 같이 늘려줘야한다는거다
그러나, 파티션의 갯수를 늘리는 기능은존재하지만
파티션의 갯수를 줄이는 기능이 없음
⇒ 한번 파티션 갯수를 늘리면 다시 줄일수가 없다
클라이언트 메타데이터
카프카 클라이언트 ← 메타데이터 응답 | 메타데이터 요청 → 카프카 클러스터
카프카 클라이언트는 리더파티션하고만 통신하는데
통신하는 리더파티션의 위치를 알기위해, 브로커한테서 메타데이터를 전달받는다
카프카 클라이언트는 무조건 브로커의 리더파티션과 통신해야한다
레코드
프로듀서가 메세지키, 메세지값 을 브로커로 보내면
브로커에서 타임스탬프, 헤더, 오프셋을 부여해서 같이 저장한다
- 타임스탬프 : 스트림프로세싱에서 활용하기 위해 ‘시간'을 저장하는 용도로 사용된다
- 오프셋 : 프로듀서가 생성한 레코드에는 존재하지않고, 브로커에 적재될때 오프셋이 저장된다.
컨슈머는 오프셋을 기반으로 처리가 완료된 데이터, 처리해야할 데이터를 구분한다(커밋을 통해 확인한다) - 헤더 : 참고할만한 메타자료 들을 같이 저장한다
- 메세지 키 : 파티션 분류를 위해서 사용한다.
[P]에서 send() 기능으로 토픽에 데이터를 보낼때, ‘어떤 번호'의 파티션에 보낼지를 결정한다
(메세지 값을 분류하려고 사용되고, 이를 파티셔닝 이라고 부른다 ) - 메세지 값 : 실질적으로 처리할 데이터가 담기는 공간.
프로듀서가 데이터를 기존형식 그대로 담아서 보낼수 없기때문에, string이나 json형태로 바꿔서 보내는 편인데(직렬화)
자료를 가져가는 컨슈머는 데이터가 어떠한 형태로 바꿔져있는지를 알아야, 원래 데이터로 다시 변환할수 있다(역직렬화)
'DATA Engineering > Kafka' 카테고리의 다른 글
섹션3. 카프카 클러스터 운영 (0) | 2022.07.20 |
---|---|
에러해결 kafka : Configured zookeeper. connect may be wrong. (0) | 2022.07.12 |
zero-copy 대신에 io_uring (1) | 2022.07.08 |
Zero-Copy는 왜 빠를까? (Kafka) (0) | 2022.07.08 |
섹션 1. 아파치 카프카의 역사와 미래 (0) | 2022.06.02 |