카프카의 내부 동작 원리와 구현
4.1 카프카 리플리케이션
카프카는 수많은 데이터 파이프라인의 정중앙에 위치하는 메인 허브 역할
중요한 메인 허브 역할을 하는 카프카 클러스터가 만약 동작하지 않는다면 전체 데이터 파이프라인에 영향을 미칠 수 있고 매우 심각한 문제를 초래할 수 있음
그래서 카프카는 한두 대에서 장애가 발생해도 안정적으로 처리할 수 있게 해주는 것이 리플리케이션
4.1.1 리플리케이션 동작 개요
카프카의 리플리케이션 동작을 위해 토픽 생성시 필숫값으로 아래의 옵션을 해줘야함
replication factor
같은 메시지를 다른 브로커들도 함께 갖고 있기 때문에 N의 리플리케이션이 있다면 N-1까지 장애가 발생해도 메시지 손실 없이 안정적으로 주고받을 수 있음
4.1.2 리더와 팔로워
동일안 리플리케이션이라 하더라도 리더만의 역할이 따로 있고, 강조한다.
카프카는 동일한 리플리케이션을 리더와 팔로워로 구분시킨다.
모든 읽기와 쓰기는 리더를 통해서만 가능하다.
프로듀서는 모든 리플리케이션에 메세지를 보내지 않고 리더에게만 메시지를 전송한다.
토픽의 파티션 수는 1, 리플리케이션 펙터 수는3
팔로워는 리더가 죽었을 때를 대비해 존재하는 것. 언제든지 리더가 될 수 있음
4.1.3 복제 유지와 커밋
리더와 팔로워는 ISR(InSyncReplica)라는 논리적인 그룹으로 묶여있음
그 이유는? 그룹 안에 속한 팔로워들만이 새로운 리더로 되도록하기 위해
데이터 일치를 위해 지속적으로 리더의 데이터를 따라가고, 리더는 ISR 내 모든 팔로워가 메시지를 받을 때까지 기다림
리더와 팔로워 중 리플리케이션 동작을 잘하고 있는지 여부의 판단 기준은?
팔로워가 특정 주기만큼 복제 요청을 하지 않는다면 리더는 해당 팔로워가 문제가 발생했다고 판단해 ISR 그룹에서 추방함 😂
하이워터마크
마지막 커밋 오프셋 위치
커밋이 되었다는 것은 리플리케이션 펙터 수의 모든 리플리케이션이 전부 메시지를 저장했음을 의미
커밋된 메시지만 컨슈머를 읽어갈 수 있음 - 메시지의 일관성을 유지함
커밋하기 전의 리더의 메시지를 읽는다면 메시지의 일관성을 유지하지 않으므로 무조건 커밋된 메시지만 컨슈머가 읽을 수 있음
모든 브로커는 재시작될 때, 커밋된 메시지를 유지하기 위해 로컬 디스크의 replication-offset-checkpoint라는 파일에 마지막 커밋 오프셋 위치를 저장함
만약 특정 토픽 또는 파티션에 복제가 되지 않거나 문제가 있다고 판단되는 경우 위 파일을 확인하고 리플리케이션되고 있는 다른 브로커들과 비교하면 찾을 수 있음
4.1.4 리더와 팔로워의 단계별 리플리케이션 동작
바쁜 리더가 리플리케이션 동작을 위해 팔로워들과 많은 통신을 주고 받으면 성능은 떨어짐
리더는 팔로워들이 오프셋 메시지를 리플리케이션하기 위해 요청했다는 사실을 알고 있음
단, 잘 받았는지 ACK를 리더에게 반환하지 않음.
RabitMQ의 트랜잭션 모드에서는 모든 미러가 메시지를 잘 받았는지 ACK를 반환함
그렇다면 어떻게 판단하냐?
만약 리더가 위와 같이 0번 오프셋에 대해 리플리케이션 동작을 마친 상태면 팔로워들은 그 다음으로 오프셋 1번 요청을 하게 될 것임
1번 오프셋 메시지에 대한 리플리케이션 요청을 받은 리더는 응답에 오프셋 message1 메시지가 커밋되었다는 내용도 함께 전달함
만약 실패했다면 0번 오프셋이 없으므로 0번을 요청하게 되고, 리더는 팔로워들이 보내는 리플리케이션 요청의 오프셋을 보고 어느 위치의 오프셋까지의 리플리케이션을 성공했는지 인지할 수 있음
(단순 궁금) 그렇다면 0번을 요청했을 때처럼 이상하게 요청시 어떻게 되는지? 바로 방출인가? 아니면 방출되는 기준치가 있나?
결론
리더의 부하를 줄위기 위해 리더와 팔로우 사이에서 ACK을 제거함. 푸시가 아닌 풀하는 방식으로 동작함
4.1.5 리더에포크와 복구
리더에포크 없이 복구를 하면 리더와 뉴리더간의 하이워터마크 싱크가 맞지 않을 때 메시지를 유실할 수 있음
리더에포크를 요청하여 하이워터마크 싱크를 응답받고 하이워터마크를 올리고 새로운 리더가 됨
둘 다 장애가 발생하고 팔로워가 먼저 복구되어 뉴 리더가 된다면 뉴 리더는 자신이 팔로워일 때의 하이워터마크와 뉴 리더일 때의 하이워터마크를 알고 있다
해결과정
팔로워는 쓰기 권한이 없으므로 뉴리더에게 리더에포크 요청을 보내 유효하지 않은 오프셋을 삭제함
리더에포크 번호는 리더가 변경될 때마다 하나씩 숫자가 증가함
4.2 컨트롤러
리더 선출을 맡음
카프카 클러스터 중 하나의 브로커가 컨트롤러의 역할을 함
파티션의 ISR 리스트 중에서 리더를 선출
ISR 리스트 정보는 주키퍼에 저장되어있음
컨트롤러는 브로커가 실패하는 것을 주시하며, 감지된다면 즉시 ISR 리스트 중 하나를 새로운 파티션 리더로 선출함
새로운 리더 정보를 주키퍼에 기록하고 변경된 정보를 모든 브로커에게 전달함
만약 파티션의 리더가 다운됐다면 리더가 없는 상태이며 카프카의 클라이언트인 프로듀서나 컨슈머가 해당 파티션으로 읽/쓰기가 불가능함
클라이언트에 설정되어 있는 재시도 숫자만큼 재시도를 함
그러므로 재시도하는 시간 내에 리더 선출 작업을 빠르게 해야함
예키지 못한 종료시 리더 선출 과정
1. 파티션의 0번의 리더가 있는 브로커 1번이 다운됨
2. 주키퍼는 1번 브로커 연결이 끊어진 후 0번 파티션의 ISR에서 변화가 생김을 감지
3. 컨트롤러는 주키퍼 위치를 통해 0번 파티션에 변화가 생긴 것을 감지하고, 해당 파티션 ISR 중 3번을 새로운 리더로 선출
4. 컨트롤러는 0번 파티션의 새로운 리더가 3이라는 정보를 주키퍼에 기록
5. 갱신된 정보는 현재 활성화 상태인 모든 브로커에게 전파
제어된 종료 과정
1. 관리자가 브로커 종료 명령어를 실행, SIG_TERM 신호가 브로커에게 전달
2. SIG_TERM 신호를 받은 브로커는 컨트롤러에게 알림
3. 컨트롤러는 리더 선출 작업을 진행, 해당 정보를 주키퍼에 기록
4. 컨트롤러는 새로운 리더 정보를 다른 브로커들에게 전송
5. 컨트롤러는 종료 요청을 보낸 브로커에게 정상 종료한다는 응답을 보냄
6. 응답을 받은 브로커는 캐시에 있는 내용을 디스크에 저장하고 종료
SIG_TERM이란?
SIGTERM은 일반적으로 시스템이 종료되거나 서비스를 재시작할 때 시스템 관리자나 슈퍼바이저 프로세스에 의해 발생한다.
이는 강제 종료(SIGKILL)와 달리, 프로세스에게 자체적으로 정리할 기회를 준다.
Docker에서 kill과 stop의 차이와 비슷
제어된 종료를 하기 위해선 controlled.shudown.enable = true
설정이 server.properties에 적용되어야함
4.3 로그(로그 세그먼트)
카프카의 토픽으로 들어오는 메시지(레코드)는 정해진 형식에 맞추어 순차적으로 세그먼트라는 파일에 저장됨
메시지 내용 및 메시지의 키, 벨류, 오프셋, 메시지 크기 등도 함께 저자오디어 브로커의 로컬 디스크에 보관됨
로그 세그먼트의 최대 크기는 1GB이며, 초과하면 기본적으로 롤링 전략을 적용함
1GB에 도달하면 해당 세그먼트 파일을 클로즈하고 새로운 로그 세그먼트를 생성함
무한히 늘어날 경우를 대비해 관리 계획을 수립해둬야함
세그먼트 삭제와 컴팩션으로 구분
4.3.1 로그 세그먼트 삭제
로그 세그먼트 삭제 옵션은 브로커의 설정 파일인 server.properties
에서 log.cleanup.policy
가 delete
로 명시되어야함
해당 값은 기본값으로 적용되며 관리자가 server.properties에 해당 옵션을 명시하지 않으면 로그 세그먼트는 삭제 정책이 적용됨
retention.ms=0
이란 로그 세그먼트 보관 시간이 해당 숫자보다 크면 세그먼트를 삭제하는 명령
로그 세그먼트는 일정 주기로 삭제 작업을 함. 기본 값은 5분 주기 ex) xxx.index
로그의 파일 명은 오프셋 번호를 의미함
ex) 00000000001.log 여기서 1은 오프셋 번호를 의미
카프카관리자는 토픽마다 보관 주기를 조정해서, 얼마만큼의 기간 동안 카프카에 로그를 저장할지 결정할 수 있음. 기본 값은 7일
4.3.2 로그 세그먼트 컴팩션
로그 컴팩션 기능을 이용하는 대표적인 예제는 카프카의 __consumer_offset 토픽
__consumer_offset
토픽은 카프카의 내부 토픽으로, 컨슈머 그룹의 정보를 저장하는 토픽
__consumer_offset
에 키(컨슈머 그룹명, 토픽명)와 밸류(오프셋 커밋 정보)형태로 메시지가 저장됨
로그 컴팩션은 메시지의 키값을 기준으로 과거 정보가 아닌 가장 마지막 값이 필요한 경우 사용함
밸류는 필숫값이지만 키는 필숫값이 아님
로그 컴팩션 기능을 사용하고 싶으면 카프카로 메시지를 전송할 때 키도 필숫값으로 전송해야함
로그 컴팩션을 통해 빠른 장애를 복구할 수 있다.
전체 로그가 아닌 메시지의 키를 기준으로 최신의 상태만 복구하기 때문에 빠르게 가능하다.
다만 모든 토픽에 적용하는 것은 좋지 않음
키값을 기준으로 최종값만 필요한 곳, 모니터링이 가능한 환경에서 사용해야함
로그컴팩션 옵션
'Message Queue > Kafka' 카테고리의 다른 글
실전 Kafka 개발부터 운영까지. 7장 카프카 운영과 모니터링 (0) | 2024.04.24 |
---|---|
실전 Kafka 개발부터 운영까지. 6장 컨슈머의 내부 동작 원리와 구현 (0) | 2024.04.22 |
실전 Kafka 개발부터 운영까지. 5장 프로듀서의 내부 동작 원리와 구현 (0) | 2024.04.21 |
실전 Kafka 개발부터 운영까지. 3장 카프카 기본 개념과 구조 (0) | 2024.04.12 |
실전 Kafka 개발부터 운영까지. 1장 카프카 개요, 2장 카프카 환경 구성 (0) | 2024.04.07 |