티스토리 뷰

 

개요

이전 포스트에서는 카프카를 구성 요소를 중심으로 리플리케이션과 파티션의 역할, 그리고 이를 활용한 고가용성과 병렬 처리의 장점에 대해 알아보았다. 고가용성 분산 스트리밍 플랫폼인 카프카는 무수히 많은 데이터 파이프라인의 정중앙에 위치하는 메인 허브 역할을 한다. 

 

이러한 메인 허브 역할을 하는 카프카가 정상 동작하지 못하면 연결된 전체 데이터 파이프라인에 영향을 주게 될 것이다. 따라서 카프카 초기 설계 단계부터 브로커 한두 대에서 장애가 발생하더라도 중앙 데이터 허브로서 안정적으로 서비스를 운영될 수 있게 리플리케이션이라는 동작을 한다. 지금부터 카프카의 매우 중요한 리플리케이션 동작 원리에 대해 파헤쳐보자

 

리더와 팔로워의 역할

카프카는 내부적으로 모두 동일한 리플리케이션들을 리더와 팔로워로 구분하고, 각자 역할을 분담시킨다. 리더는 리플리케이션 중 하나가 선정 되며, 모든 읽기와 쓰기는 리더를 통해서만 가능하다. 즉, 프로듀서는 모든 리플리케이션에 메시지를 보내는 것이 아니라 리더에게만 메시지를 전송하고 컨슈머도 오직 리더를 통해 메시지를 가져온다.

 

현재 그림을 보면 peter-test01 토픽의 파티션 수는 1개이고, 리플리케이션 팩터 수는 3개이다. 

 

프로듀서는 peter-test01 토픽으로 메시지를 전송하는데, 리더만 읽고 쓰기가 가능하므로 0번 파티션의 리더로 메시지를 보낸다. 리더만 읽고 쓰기 동작을 한다고 나머지 팔로워들이 그저 대기만 하는 것이 아니라, 리더에 문제가 발생한 경우를 대비하여 언제든 새로운 리더가 될 준비를 해야한다.

 

즉, 지속적으로 파티션의 리더가 새로운 메시지를 받았는지 확인하고, 새로운 메시지를 리더로부터 복제해와야한다.

 

 

리더와 팔로워 커밋

리더와 팔로워는 ISR(InSyncReplica)이라는 논리적인 그룹으로 묶여있다. 해당 그룹에 속한 팔로워들만 새로운 리더의 자격을 가질 수 있는 것이다.

 

팔로워가 특정 장애(네트워크 오류, 브로커 장애 등)가 발생하여 리더로부터 리플리케이션을 하지 못하여 데이터가 불일치하는 상황이 발생하고, 만약 이 상태에 팔로워에게 새로운 리더를 넘겨주게 된다면 데이터 정합성이나 메시지 손실이 발생할 것이다.

 

따라서 리더는 읽고 쓰는 동작은 물론, 팔로워가 리플리케이션을 잘하고 있는지도 판단한다. 만약 팔로워가 특정 주기 시간 만큼 복제를 요청하지 않는다면 리더는 해당 팔로워가 문제가 발생했다고 판단해 ISR 그룹에 추방한다.

 

또한 리더는 ISR내에서 모든 팔로워들이 복제를 완료했다면, 리더는 내부적으로 커밋되었다는 표시를 하게 된다. 이렇게 커밋된 메시지만 컨슈머가 읽어갈 수 있다.

커밋된 메시지만 컨슈머가 읽는다.

Kafka 메시지 커밋 - 데이터 정합성을 유지하는 방법

프로듀서가 메시지를 리더에게 전송하면 컨슈머가 바로 읽으면 되는데, 왜 커밋된 메시지(팔로워가 모두 리플리케이션한 상태)만 컨슈머가 읽을 수 있는지 의문이 생길 것이다.

 

만약 커밋되기 전 메시지를 컨슈머가 읽을 수 있다고 가정을 해보겠다.

리더 변경 전

 

컨슈머 A가 peter-test01 토픽을 컨슘하고 있고, 컨슈머가 커밋되기 전 메시지를 읽어갈 수 있다고 가정하였으니, test message1, 2를 읽을 것이다.(test message2는 리플리케이션 동작 전)

 

리더 변경 후

그런데 토픽의 파티션 리더가 있는 브로커가 장애가 발생하여 ISR 그룹 내의 새로운 리더가 할당되었다. 컨슈머 B는 test  message 2가 리플리케이션 되지 않은 새로운 리더의 메시지를 읽게되어 test message1만 읽게된다.

 

컨슈머 A와 B는 같은 토픽의 파티션을 읽었지만 컨슘한 메시지는 일치하지 않는 현상이 발생했다.

 

카프카에서는 이러한 메시지 불일치 현상을 방지하고자 커밋된 메시지(팔로워가 모두 리플리케이션한 메시지)만 컨슈머가 읽을 수 있도록 하는 것이다.

 

 

리더와 팔로워의 단계별 리플리케이션 동작

각 파티션에서 어떻게 메시지를 리플리케이션을 하는 걸까? 



이 그림에서 peter-test01 토픽이 파티션 1개와 3개의 리플리케이션 팩터를 가지고 있음을 알 수 있다. 또한 현재 리더만 0번 오프셋에 message1이라는 메시지를 갖고 있다. 프로듀서가 peter-test01토픽으로 message1이라는 메시지를 전송했으며, 리더만 저장하고 팔로워들은 아직 리플리케이션 하기 전 상태이다.

 

 

팔로워들은 리더에게 0번 오프셋 메시지를 가져오기(fetch) 요청을 보낸 후 새로운 메시지 message1이 있다는 사실을 인지하고 message1을 리플리케이션 한다.

 

그러나 리더는 팔로워들이 0번 오프셋에 대한 리플리케이션 동작이 성공했는지 실패했는지 알 수 없다.

RabbitMQ(전통적인 메시징 큐)의 트랜잭션 모드에서는 모든 미러(카프카에서 팔로워)가 메시지를 받았지 확인하는 ACK를 팔로워에서 리더로 리턴하므로 팔로워들이 메시지를 받았는지 알 수 있다.

 

카프카의 경우에는 리더와 팔로워간 ACK를 주고 받는 통신이 없다. 그렇다면 어떻게 팔로워들이 성공적으로 받았는지 확인할까?

 

 

다음 그림을 확인하면 알 수 있다. 리더는 1번 오프셋 위치에 새로운 메시지인 message2를 프로듀서로부터 받아 저장한다.

0번 오프셋에 대한 리플리케이션 동작을 마친 팔로워들은 리더에게 1번 오프셋에 대한 리플리케이션 요청을 할 것이다. 그러면 리더는 오프셋 0번에 대한 리플리케이션은 모두 성공했음을 인지하고 오프셋 0번에 대해서 커밋을 하고 하이워터 마크를 증가한다.

 

하이워터마크: 마지막 커밋 오프셋 위치

 

이후, 모든 팔로워들 부터 1번 오프셋 메시지에 대한 리플리케이션 요청을 받은 리더는 응답에 0번 오프셋 message1 메시지가 커밋되었다는 내용과 함께 전달하여 팔로워들도 리더와 동일한 커밋 표시를 하게된다. 그리고 나서 오프셋1인 message2 메시지도 레플리케이션하고 이와 같은 과정을 계속 반복하게 된다. 

 

다른 메시징 시스템들과 다르게 ACK통신을 제거하여 통신 비용을 줄이고, 그럼에도 팔로워와 리더 간의 리플리케이션 동작을 신뢰할 수 있게 만든것을 알 수 있다.

 
 
 
 
 
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함