티스토리 뷰
Kafka Replication
카프카에서 Replication이란 각 메시지들을 여러개로 복제해서 카프카 클러스터 내 브로커들에 분산 시키는 동작을 의미한다.
이러한 Replication 덕분에 하나의 브로커가 종료되더라도 카프카는 안정성을 유지할 수 있다.
replication factor 옵션을 통해 복제할 브로커의 수를 지정할 수 있다.
factor 수가 커지면 안정성은 높아지지만 그만큼 브로커 리소스를 많이 사용하게된다.
일반적으로 테스트나 개발환경은 1, 운영환경에서 로그와 같이 유실이 허용되는 메시지는 2, 유실이 허용되지 않는 메시지는 3으로 설정하는 것이 권장된다.
대규모 서비스에서도 3으로 충분히 안정성을 확보하여 가용된다고 한다.
Replication이 필요한 이유
카프카(Kafka)는 수많은 데이터 파이프라인의 중심에 위치하며, 메인 허브 역할을 수행한다.
이러한 중앙 허브 시스템에 장애가 발생할 경우, 전체 시스템의 장애로 확산될 위험이 크다.
이를 방지하기 위해 카프카는 Replication(복제) 기능을 제공한다.
클러스터 내 브로커 한두 대에 장애가 발생하더라도, 데이터의 복제본을 사전에 다른 브로커에 저장해 두어 데이터를 보호할 수 있다.
또한 Leader-Follower 구조를 통해, 장애가 발생한 리더 브로커를 빠르게 대체하여 시스템의 안정성과 가용성을 유지할 수 있다.
leader와 follower
Topic의 메시지는 Partition 단위로 독립적으로 처리된다.
카프카는 각 Parition에 대해 leader 브로커와 follower 브로커를 구분하여 관리한다.
leader 브로커만이 메시지를 읽기, 쓰기가 가능하며
follower 브로커는 leader와 통신하며 메시지를 복제 저장하는 처리만 수행하며
leader 브로커 장애시 leader로 승격되어 leader 역할을 수행하게 된다.
따라서 Producer는 leader 브로커에 메시지를 전송하고, Consumer 또한 leader 브로커를 통해서만 메시지를 가져온다.
ISR(In Sync Replica)
ISR은 리더와 데이터 동기화가 완료된 팔로워 브로커들로 구성된 복제 그룹(Replication Group)이다.
ISR이라는 그룹의 존재 이유는, 리더 장애시 해당 그룹 내에 있는 팔로워, 즉 동기화가 이루어진 브로커만이 leader로 승격되어 메시지 유실 밀 중복 처리 없이 진행하기 위함이다.
ISR 내의 팔로워들은 리더와 데이터 일치를 유지하기 위해 지속적으로 리더의 데이터를 따라가게 되고,
리더는 ISR 내 모든 팔로워가 메시지를 받을 때까지 기다린다.
만약 팔로워 브로커의 일시적인 오류로 특정 시간 안에 복제 요청을 하지 않는다면 리더는 팔로워에 문제가 발생했다고 판단하여 ISR에서 추방한다.
추후 장애에 복구하여 데이터 동기화에 따라온다면 다시 ISR 그룹에 포함될 수 있다.
복제완료 여부 구분
우선 replication.factor=3, min.insync.replicas=2라고 하겠다.
- 복제 구성
- replication.factor=3이므로, 하나의 파티션은 총 3개의 복제본을 가진다.
- 1개의 리더(Leader)
- 2개의 팔로워(Follower)
- 초기 상태에서 이들 모두가 ISR(In-Sync Replica)에 포함된다.
- replication.factor=3이므로, 하나의 파티션은 총 3개의 복제본을 가진다.
- 복제 커밋 조건
- min.insync.replicas=2 설정에 따라, 커밋되기 위해서는 ISR 내 최소 2개의 복제본(리더 포함)에 복제 완료해야 한다.
- 복제 커밋
- 이 조건이 충족되면, 리더는 커밋되었다는 표시를 한다.
- 마지막 커밋 오프셋 위치인 High Water Mark 표기
위와 같은 과정을 통해 컨슈머는 커밋된 메시지만 읽어갈 수 있다.
커밋(복제)되지 않은 메시지를 컨슈머가 읽을 수 없게 하는 이유는 메시지의 일관성을 위해서이다.
만약, 복제되지 않은 메시지를 읽어갔을 때 어떤 상황이 발생하는지 알아보자.
Topic에 대한 Consumer Group이 2개 이상이 존재하는 상황에서
한 그룹의 Consumer는 메시지를 처리하고, 다른 그룹은 아직 처리하지 않았다고 해보자.
이때, 리더가 장애가 발생하여 다른 팔로워가 리더로 승격하게 되면
팔로워에는 메시지가 복제되지 않았으므로 어떤 그룹은 이전의 메시지를 처리하고 어떤 그룹은 처리하지 못한채로 다음 메시지를 처리하게 될 것이다. 데이터의 일관성이 깨지는 현상이 발생하게 된다.
따라서 kafka는 데이터의 일관성을 위해 ISR 내에서 High Watermark를 통해 복제 완료 여부를 구분한다.
복제 완료를 구분하기 위해 High Watermark를 표기한다는 것에 대해서는 알았는데,
이를 위해서는 각 브로커가 자신이 어디까지 복제했는지를 추적하고 기록할 필요가 있다.
그래야 리더가 ISR 내 브로커들의 복제 상태를 정확히 파악하고, HWM을 올바르게 계산할 수 있다.
팔로워 브로커는 이러한 복제 상태를 지속적으로 기록하기 위해,
자신의 로컬 디스크에 replication-offset-checkpoint 파일을 사용하여 마지막으로 복제한 오프셋을 저장한다.
이 파일은 특히 브로커가 재시작될 때, 이전 복제 위치를 기억하고 빠르게 복제를 재개하는 데 중요한 역할을 한다.
Replication 동작 과정
1. 프로듀서 데이터 전송
- 프로듀서는 해당 파티션의 리더 브로커로 메시지를 전송합니다.
- acks 설정에 따라 리더는 어떤 조건에서 응답을 줄지 결정:
- acks=0: 복제 여부 상관없이 응답 안 함
- acks=1: 리더만 쓰기 성공하면 응답
- acks=all/-1: 리더 + min.insync.replicas 이상 복제되면 응답
2. 팔로워 → 리더로 요청
- 팔로워는 주기적으로 리더에게 Fetch 요청을 보내, 새로운 데이터를 가져감.
3. 복제 완료 판단 및 하이워터마크 설정
- 팔로워가 fetch 요청을 보낼 때, 새롭게 읽어갈 offset 위치를 전달한다.
- 이를통해 leader는 offset 이전까지 follower가 데이터를 읽어갔다고 판단한다.
- 다른 팔로워 브로커에게도 동일한 offset에 대해 fetch 요청을 받는다면 복제가 완료됬다고 판단하고 commit을 진행한다.
- commit을 통해 복제 완료된 오프셋+1으로 High Water Mark(HWM)를 표기한다.
4. 팔로워 상태 추적
- 각 팔로워는 자신이 어디까지 복제했는지를 로컬 디스크의 replication-offset-checkpoint 파일에 저장합니다.
- 브로커 재시작 시 이 파일을 통해 복제 위치를 복구합니다.
5. ISR 유지 및 관리
- 일정 시간(replica.lag.time.max.ms) 동안 팔로워가 리더와의 복제 속도를 따라가지 못하면, ISR에서 제외됩니다.
- ISR에 들어오지 못한 팔로워는 리더 승격 대상에서 제외됩니다.
- 팔로워가 리더와 다시 동기화되면 ISR로 재편입됩니다.
"팔로워가 fetch 요청을 보낼 때, 새롭게 읽어갈 offset 위치를 전달한다."는 부분이 kafka와 다른 메시지 큐와 큰 차이점이다.
Rabbit MQ와 같은 메시지 큐는 fetch 이후 ack 응답을 통해 복제 완료 했음을 알리는데,
kafka는 ack 없이 새롭게 읽어갈 offset을 fetch 요청에 함께 전달함으로써, 이전 offset 까지는 동기화가 이루어졌음을 전달한다.
만약에 메시지가 만개라면 Rabbit MQ는 2만개의 요청을 주고 받아야하지만,
Kafka는 10001개의 요청으로 복제과정을 진행할 수 있다.
이러한 처리 방식으로 인해 kafka가 빠른 메시지 처리 성능을 갖추게 된 것이다.
또한 leader 브로커는 메시지 읽고 쓰기와 같은 많은 처리를 해야하므로,
leader가 push하는 것이 아닌 follower가 pull하는 방식을 통해 leader 브로커의 부하를 줄였다.
Leader Epoch
리더 에포크는 카프카의 파티션들이 복구 동작을 할 때, 메시지의 일관성을 유지하기 위한 용도로 사용된다.
복제 과정에서 리더와 팔로워간 오프셋 요청과 응답을 통해 하이워터마크 값을 올리며 동기화를 진행한다.
팔로워는 리더에 오프셋 요청을 통해 메시지를 가져가며 이때 리더의 HWM의 변화를 감지하여 자신의 HWM도 증가시킨다.
리더는 오프셋 요청 이후에 팔로워가 잘 가져갔다고 판단하여 HWM을 증가시킨다.
팔로워는 리더보다 HWM이 1보다 작게 된다.
이후에 한번 더 요청하여 HWM을 증가시킨다.
팔로워와 리더의 HWM이 같아지려면 리더가 새로운 메시지를 전송 받지 않은 상태에서, 팔로워가 한번 더 오프셋 요청을 하는 경우다.
즉, 리더가 신규 메시지를 받지 않은 상태에서 팔로워의 오프셋 요청이 이뤄져야 비로소 HWM이 같아진다.
팔로워는 늘 리더를 따라가는 입장이기에 신규 메시지가 발행되면 항상 HWM이 작게 된다.
이런한 구조로 인해 리더가 장애가 발생하거나 재시작으로 인해 일시 중단되어 팔로워가 리더로 승격된 경우,
팔로워는 오프셋 요청으로 가져온 메시지에 대해 아직 HWM을 증가시키지 못한 경우,
해당 메시지는 모두 삭제 시킨다.
메시지 유실이 발생하는 것이다.
재시작하는 상황이거나, 일시적인 장애라면 해당 메시지를 유실하는 것은 큰 손해일 수 있다.
따라서, 리더 에포크를 사용하게 되면 메시지를 즉시 삭제하지 않고 이전 리더에게 리더 에포크를 요청하여
리더가 복구 됬다면 이전 처럼 하이워터 마크를 올리는 작업을 수행하여 정상 복제된 메시지임을 판단한다.
Controller
leader-follower는 파티션 단위로 선출되는 브로커라면,
Controller는 전체 클러스태 내에서 하나의 브로커가 담당한다.
Controller는 주키퍼에 저장된 ISR 리스트 정보를 통해 리더 브로커 장애 발생시, 새로운 리더를 선출하게 된다.
리더 선출 과정(파티션 리밸런싱)
- 특정 ISR의 리더 브로커 장애 발생
- 주키퍼는 특정 ISR의 리더 브로커와 연결이 끊어진 것을 판단함
- 컨트롤러는 주키퍼를 통해 ISR의 변화가 일어남을 감지하고, 해당 ISR의 새로운 리더를 선출
- 컨트롤러가 주키퍼에 새로운 리더 기록
- 모든 브로커에 해당 정보 전달
Kafka는 위와 같은 과정을 매우 빠르게 진행한다.
리더 브로커의 장애가 발생하면 Consumer는 아무런 처리를 하지 못하게 된다.
따라서 Consumer의 재시도 시간 내에 빠르게 처리를 해줘야 높은 가용성을 갖춘 서비스가 된다.
다행이 kafka는 이러한 과정이 수초 이내에 끝날만큼 빠르게 진행을 해준다.
'소프트웨어 > kafka' 카테고리의 다른 글
[Spring Kafka 연동] 전송방식 설정부터 에러처리 핸들링까지 (3) | 2025.08.03 |
---|---|
[Kafka] Consumer의 동작 원리 (1) | 2025.08.01 |
[Kafka 개념] Producer의 동작 원리 (1) | 2025.07.31 |
[Kafka 개념] 카프카 아키텍쳐 (2) | 2025.07.28 |
kafka-UI 툴 사용법 (2) | 2025.07.26 |