용로그
article thumbnail

들어가며


이번 글에서는 카프카의 큰 구성 요소인 프로듀서(Producer), 브로커(Broker), 컨슈머(Consumer)와 전달받은 메시지가 어떻게 관리되는지를 알아본다.

 

Producer


Producer는 메시지를 생성해서 카프카의 토픽으로 메시지를 보내는 애플리케이션이다. 여기서 Producer가 카프카에게 메시지를 전달하게 되면 카프카는 ACK/NACK로 응답을 반환한다.

 

Brokers


Kafka는 Producer와 Consumer 사이에서 메시지를 중계한다. Producer와 Consumer는 별도의 애플리케이션으로 만들어진 반면, Broker는 Kafka 그 자체이기 때문에 Kafka Broker는 일반적으로 Kafka라고 불리는 시스템을 의미한다. 따라서 Kafka와 Kafka Broker는 서로 동일하다.

 

Zookeeper

Zookeeper(주키퍼)는 카프카에 필수적인 요소라고 할 수 있다. 주키퍼는 Apache 프로젝트 중 하나로 Hadoop Echosystem(하둡 에코 시스템)을 구성한다. 주로 분산 시스템의 메타 정보를 관리하고 필요시에는 분산 시스템의 마스터를 선출하는 역할을 담당한다.

 

동일한 Zookeeper 클러스터에 멀티 카프카 클러스터를 구성하는 모습이다.

 

예를 들어 Kafka Cluster를 구축하면 Zookeeper에는 Kafka Cluster의 식별 정보로부터 현재 살아있는 Broker 정보, 나아가 권한 정보 등이 저장된다. 또한 Kafka Broker들 중 일종의 지휘자 역할을 하는 Controller 브로커를 뽑는 역할도 담당한다.

 

Kafka(Broker) Cluster 구성


Kafka Cluster를 조금 더 소개해보겠다. 실제 서비스에서 사용되는 Kafka는 HA를 위해 여러개의 Kafka 서버와 Zookeeper로 구성된 Cluster 구조로 사용된다고 했다.

 

일반적으로 3개 이상의 Kafka로 구성되며, 이러한 구조를 통해 Broker에 저장된 메시지를 다른 Broker에게 공유하고 하나의 Broker에 문제가 생겼을 때, 다른 Broker로 그 역할을 대체해서 시스템을 정상적으로 유지시키는 방식으로 동작한다.

 

각각의 Kafka 서버를 Kafka Broker라고 부르며, n개의 Broker 중 1대는 리더 역할을 수행한다.

 

따라서 Zookeeper라는 분산 애플리케이션의 데이터 관리 기능을 가지고 있으며, 여러 개의 Broker들을 컨트롤해 주는 역할을 수행한다. 때문에 Zookeeper 없이 Kafka Cluster가 동작할 수 없다는 특징이 있다.

 

Kafka 진영은 Zookeeper와 너무 강한 의존성을 가지는 문제 때문에 자체적으로 코디네이터 역할을 수행할 수 있도록 하기 위해 노력하고 있다.

 

Consumer


Consumer는 토픽(Topic) 내부의 파티션에 저장된 데이터를 가져오는 역할을 한다. Kafka에서 데이터를 Consume하는Consume 하는 방식은 Polling 방식이다.(Consumer가 데이터를 Consume 하는 방식) 파티션으로부터 데이터를 가져오면서 offset 위치를 기록하는 역할도 한다.

 

offset이란 파티션에 있는 데이터의 고유한 번호를 뜻하며, Consumer가 offset을 저장함으로써 데이터를 어디까지 읽었는지 확인할 수 있고, 저장된 offset이 있기 때문에 Consumer가 멈추는 상황이 발생하더라도 재시작되었을 때 중지된 시점부터 데이터를 읽어올 수 있다.

 

Consumer가 데이터를 polling할 때 어디까지 읽었는지 commit 하게 되는데, commit 한 offset 정보는 consumer_offset 토픽에 저장되며, offset은 각 토픽의 각 파티션별로 따로 지정된다.

 

Consumer는 Consumer 그룹을 통한 데이터 병렬처리로 인해 데이터를 빠르고 효과적으로 처리할 수 있는데, 중요한 내용은 하나의 토픽에 대한 Consumer 개수는 파티션의 개수보다 적거나 같아야 한다. Consumer가 더 많을 경우 더 이상 할당될 파티션이 없기 때문에 남은 Consumer는 동작하지 않게 된다.

 

Kafka의 메시지


Kafka의 메시지는 Key(키)와 Value(값)로 구성된다. 메시지의 키는 해당 메시지가 Kafka Broker 내부에 저장될 때 위치와 관련된 요소이다. Producer가 메시지를 Broker로 전달할 때, Producer 내부의 파티셔너(Partitioner)가 저장 위치를 결정하는데, 이때 키의 값을 이용하여 연산하고 그 결과에 따라 저장되는 위치를 결정한다.

 

메시지의 값은 메시지가 전달하고자 하는 내용물을 의미한다. 값은 단순한 문자열이 될 수도 있고, json이나 특정 객체가 될 수 있다. 참고로 이렇게 다양한 타입의 값을 보낼 수 있는 것은 Broker를 통해 메시지가 발행되거나 소비될 때, 메시지 전체가 직렬화/역직렬화되기 때문이다.

 

Kafka의 메시지 구조

메시지의 키와 값은 다양한 타입이 될 수 있지만, 특정한 구조인 스키마(schema)를 가진다. Kafka 메시지의 스키마는 데이터베이스의 테이블 스키마와 유사한 개념이다.

 

이는 Producer가 발행하고 Consumer가 소비할 때 메시지를 적절하게 처리하기 위해 필요하다. 예를 들어 Producer가 내용(값)이 json 형태인 메시지를 발행할 때, 해당 메시지를 소비하는 Consumer는 Producer가 생산한 json 구조를 예상하고 그에 맞게 메시지를 처리하려고 한다.

 

이때 만약 Producer와 Consumer가 메시지에 대한 서로 다른 스키마를 가지고 있다면, 정상적인 처리를 할 수 없다. 이처럼 스키마는 Kafka 개발, 운영에서 굉장히 중요한 역할을 담당한다.

 

Topic


Kafka의 토픽은 메시지를 구분하는 논리적인 단위로, 동일한 토픽의 메시지들은 논리적으로 같은 문맥(context)을 가진다. 예를 들어, 주문에 관한 내용을 담고 있는 메시지를 발행하고, 소비하기 위해서 우리는 order라는 토픽을 생성하고 이 토픽을 기준으로 메시지를 발행, 소비할 수 있다.

 

이처럼 토픽은 논리적인 단위이자 메시지 흐름의 단위이기도 하다. 그렇기 때문에 토픽을 설계할 때는 메시지의 논리적인 구분을 명확하게 해야 한다.

 

Partition


논리적인 단위인 토픽을 기준으로 발행되는 메시지들은 Broker 내부의 물리적인 단위의 파티션(partition)으로 나뉜다. 즉, 모든 토픽은 각각 대응하는 하나 이상의 파티션이 브로커에 구성되고, 발행되는 토픽 메시지들은 파티션들에 나뉘어 저장된다.

 

T0 토픽은 4개의 파티션, T1 토픽은 2개의 파티션으로 구성된 모습이다.

이렇게 하나의 토픽에 대하여 여러 파티션을 구성하는 가장 큰 이유는 분산 처리를 통한 성능 향상에 있다.

 

Kafka는 하나의 토픽에 대해 여러 Producer가 발행할 수 있고 여러 Consumer가 구독할 수 있다. 그렇기 때문에 토픽을 하나의 Partition으로 구성하면, 무수한 발행-구독 요청을 하나의 파티션이 처리해야 한다.

 

물론 Kafka는 하나의 Partition으로도 충분한 성능을 발휘할 수 있지만, 일반적으로 2개 이상의 파티션을 서로 다른 Broker는 병렬 구성하여 요청의 부하를 분산시켜 준다. 이에 따라 자연스럽게 해당 토픽에 관한 성능도 향상할 수 있다.

Partition Replication


하나의 토픽은 하나 이상의 파티션으로 구성된다. 더 나아가 Kafka는 서비스 안정성과 장애 수용(Fault-Tolerance)에 관한 요소로 파티션의 복제(Replication) 기능을 제공한다.

 

하나의 파티션은 1개의 리더 레플리카와 그 외 0개 이상의 팔로워(follower) 레플리카로 구성된다. 리더 레플리카는 파티션의 모든 쓰기,. 읽기 작업을 담당한다.

 

반대로 팔로워 레플리카는 리더 레플리카로 쓰인 메시지들을 그대로 복제하고, 만약 리더 레플리카에 장애가 발생하는 경우, 리더 자리를 승계받는다.

 

참고로 승계받을 준비가 된 즉, 리더 레플리카의 메시지를 적절하게 복제하여 리더 레플리카와 동기화된 레플리카들의 그룹을 ISR(In-Sync Replica)라고 한다.

 

파티션의 레플리카 수는 복제 계수(Replication Factor)를 통해 결정되는데, 만약 복제 계수가 1이라면 파티션은 리더 레플리카로만 구성된다. 이때 파티션과 리더 레플리카는 별개인 것이 아니라 동일한 것으로 볼 수 있다.

 

즉, 일반적으로 말하는 물리적인 파티션은 리더 레플리카를 이야기한다고 할 수 있다. 나아가 복제 계수가 2개 이상이라면 해당 파티션은 1개의 리더 레플리카와 1개 이상의 팔로워 레플리카로 구성된다. 이 경우 모든 레플리카들은 서로 다른 브로커에 구성된다.

 

만약 같은 파티션의 레플리카가 동일한 브로커에 구성되는 경우에는 에러가 발생한다.

 

이처럼 파티션의 레플리카들은 언제 발생할지 모르는 장애에 대비해 데이터 유실을 방지하고 지속적인 서비스를 제공하기 위해 구성한다.

'Apache > Kafka' 카테고리의 다른 글

[Kafka] 카프카가 고가용성을 유지하는 방법  (0) 2024.03.03
profile

용로그

@용로그

벨덩보단 용덩 github.com/wonyongChoi05