토픽(Topic)과 파티션(Partition), 세그먼트 파일(Segment File)
카프카에서 전달되는 메시지 스트림의 추상화된 개념을 토픽(Topic)이라고 한다. 프로듀서는 메시지를 특정 토픽에 발행한다. 컨슈머는 특정 포틱에서 발행되는 메시지를 구독할 수 있다.
프로듀서가 메시지를 특정 토픽에 전송하면 카프카 클러스터는 토픽을 좀 더 세분화된 단위인 파티션(Partition)으로 나누어 관리한다. 기본적으로 프로듀서는 발행한 메시지가 어떤 파티션에 저장되는지 관여하지 않는다. 각 파티션은 카프카 클러스터를 구성하는 브로커들이 나눠 갖는다.
특정 파티션으로 전달된 메시지는 오프셋(Offset)이라고 하는 숫자가 할당된다. 오프셋은 해당 파티션에서 몇 번째 메시지인지 알 수 있는 ID라고 보면 된다. 컨슈머는 오프셋을 이용해서 자신이 어디까지 읽었는지 판단한다. 오프셋은 파티션 내에서 유일한(Unique) 값을 갖느다.
카프카 브로커는 파티션에 저장된 메시지를 파일 시스템에 저장한다. 이때 만들어지는 파일이 “세그먼트 파일(Segment File)”이다. 기본적으로 1GB까지 세그먼트 파일이 커지나 일정 시간이 지나면 파일을 다시 만든다. 보존기간이 지난 메시지가 지워질 때 세그먼트 파일 단위로 지워진다.
파티션의 복제(Replication)
카프카는 고가용성(High Availability)을 제공하기 위해 파티션 데이터의 복사본(Replication)을 유지할 수 있다. 몇 개의 복사본을 저장할 것인지는 리플리케이션 팩터(Replication Factor)로 저장할 수 있으며 토픽별로 다르게 설정할 수 있다.
만약 토픽의 리플리케이션 팩터를 N으로 설정하면 N개의 파티션 데이터 복사본이 생성되고 카프카 브로커가 겹치지 않게 나눠 갖는다. N개의 복사본은 리플리카(Replica)라고 하며, N개 중 1개의 리플리카가 리더(Leader)로 선정되어 클라이언트의 요청을 담당한다. 나머지 N-1개의 리플리카는 팔로워(Follower)가 되어 리더의 변경사항을 따라가기만 한다. 프로듀서와 컨슈머의 쓰기, 읽기 요청은 리더 리플리카에만 전송되며 클라이언트 설정에 따라 팔로워들에게 전송되기까지 기다릴 수도 있고, 리더에게만 전송될 수도 있다.
프로듀서(Producer)와 컨슈머(Consumer), 컨슈머 그룹(Consumer Group)
카프카의 클라이언트는 기본적으로 프로듀서(Producer)와 컨슈머(Consumer)라는 두 가지 분류가 존재한다.
프로튜서(Producer)는 메시지를 생성하여 카프카에 전달하는 클라이언트를 의미한다. 프로듀서가 특정 토픽에 메시지를 전송하면 기본적으로 여러 파티션에 번갈아가며 전송되어 파티션을 골고루 사용하게 된다. 전송 순서가 중요한 메시지의 경우 키(Key)값을 할당하고 이 키를 기반을 특정 파티션에 전송되도록 파티셔너를 작성할 수도 있다.
프로듀서에서 유의해야 할 점은 서로 다른 파티션으로 전송된 메시지의 소비 순서는 보장되지 않는다는 것이다. 만약 메시지의 처리 순서가 중요한 경우라면 메시지 키와 파티셔너를 이용해 두개의 메시지가 같은 파티션으로 전송되도록 추가하는 작업이 필요하다. 즉, 카프카로 전송된 메시지는 같은 파티션일 경우에만 순서가 보장된다.
컨슈머(Consumer)는 메시지를 카프카로부터 읽어가는 클라이언트다. 카프카 컨슈머는 컨슈머 그룹(Consumer Group)을 형성한다. 카프카의 토픽은 컨슈머 그룹 단위로 구독되어진다. 토픽의 파티션은 컨슈머 그룹당 오로지 하나의 컨슈머의 소비만 소비될 수 있다. 파티션과 컨슈머의 이런 연결을 소유권(Ownership)이라고 부른다. 다시 말해서 같은 컨슈머 그룹에 속한 컨슈머들이 동시에 동일한 파티션에서 메시지를 읽어갈 수 없다.
파티션과 컨슈머의 소유권 관계는 브로커와 컨슈머의 구성이 변경되지 않는 이상 계속 유지된다. 즉, 컨슈머 그룹에 컨슈머가 추가 혹은 제거된 경우 컨슈머 그룹 내에서 파티션의 소유권을 재분배하는 리밸런싱(Rebalancing) 과정이 실행된다. 리밸런싱을 통해 컨슈머 그룹 내의 컨슈머들이 파티션을 고르게 할당 받아 소비할 수 있게된다. 카프카 클러스에 브로커가 추가/제거 되는 경우 전체 컨슈머 그룹들에서 리밸런싱이 발생한다.
컨슈머 그룹의 컨슈머 수가 토픽의 파티션 수보다 많은 경우, 파티션 개수만큼의 컨슈머만 동작하며 나머지 잉여 컨슈머들은 놀게 된다. 따라서 파티션 개수와 컨슈머 그룹내 컨슈머 개수의 적절한 조정이 필요하다.
컨슈머 그룹는 각 파티션에 대해 오프셋(Offset)을 할당받는다. 이 오프셋은 파티션에 저장된 메시지에 할당된 오프셋 값으로 컨슈머 그룹이 해당 파티션에서 어디까지 읽었는지를 의미한다. 따라서 특정 컨슈머 그룹에 컨슈머가 추가, 제거되어 리밸런싱이 일어났을 때 다른 컨슈머가 파티션을 할당받아도 내 컨슈머 그룹이 어디까지 얽었는지 기록이 유지되기 때문에 이어서 처리할 수 있게 된다.
컨슈머가 카프카로부터 메시지를 읽어서 처리한 다음 “여기까지 읽었어요”라고 컨슈머 그룹에 할당된 오프셋을 변경하는 작업을 오프셋 커밋(Commit)이라고 한다. 오프셋 커밋을 잘 처리하지 않으면 카프카 클라이언트를 사용하는 애플리케이션에서 메시지 누락이 발생하거나 불필요한 중복 처리가 발생할 수 잇으므로 잘 이해하고 사용해야 한다.
참조링크
- https://velog.io/@jaehyeong/Apache-Kafka%EC%95%84%ED%8C%8C%EC%B9%98-%EC%B9%B4%ED%94%84%EC%B9%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80
- https://soft.plusblog.co.kr/3