본문 바로가기

IT/OpenSource

[Apache Kafka]Kafka Consumer Group에 대한 고찰(2023.03.30)

0. Table Of Contents

 

 

1. Consumer Group이란 무엇인가

Consumer Group이란, Consumer Instance를 대표하는 그룹이며 아래 그림을 참조한다.

  • Consumer (Instance) : Broker로부터 데이터를 pull 받아 처리하는 단일 process.
  • Offset : Partition의 데이터 위치를 표시하는 pointer. Consumer는 offset을 이용해 어디까지 데이터가 소비되었는지 알 수 있다.

 

 

 

 

2. Consumer Group이 왜 필요한가

2.1. Consumer Failover

1번 섹션의 그림을 떠올리면서 아래 그림을 참조해보자.

 

 

 

 

위 첫번째 그림의 경우, Broker에 저장되어 있는 Topic A의 Message를 하나의 Consumer Instance에서 가지고 가고 있는 상황이다. 위 상황에서 두번 째 사진과 같이 Consumer Instance가 장애가 날 시 제대로 된 Data Consume을 할 수 없다. 그렇기 때문에 Group에는 여러개의 인스턴스를 포함하여 그룹 내부에서 다른 인스턴스가 대체할 수 있도록 해야한다.

 

 

위 그림은 Consumer Group 중 하나가 장애가 난 상황이다. 그러나 이 그림은 앞서 설명한 그림과는 다르게 4개의 Consumer Instance로 구성되어있기 때문에 Consumer A의 역할을 다른 Instance가 처리 할 수 있게 된다. 이러한 이유로 인해 Consumer Group을 구성하여 시스템 안정성을 확보하는 것이 중요하다.

 

 

2.2. 다수의 Instance에서의 Offset 관리

Kafka는 내부적으로 각 topic마다 어디까지 message가 소비되었는지에 대한 pointer를 offset이라는 요소로 관리하게 된다. 그림으로 그려보면 아래와 같은 형태이다.

 

 

 

 

 

2.2.1. 독립적인 Consumer로 구성하였을 경우

 

 

위 사진을 참고하며 아래와 같은 시퀀스를 생각해보자.

  • Consumer A, B 모두 서버측에서 관리되고 있는 offset은 3이다.
  • Consumer A가 pull 받아서 broker의 offset을 4로 변경하였다.
  • Consumer B가 뒤이어 pull 받으려 하지만, 서버측에 저장되어 있는 offset이 3이기 때문에 병렬 처리가 되지 않는다.

 

 

 

2.2.2. 같은 Consumer Group의 Instance로 구성하였을 경우

 

이 경우, consumer group으로 관리를 하기 때문에 offset 정보를 다른 Consumer Instance간 공유를 하게된다. 따라서 병렬처리를 할 때, offset이 꼬이지 않고 데이터의 손실이 없이 운영될 수 있다.

 

3. Consumer Group과 Partition의 관계

 

결론부터 말하면 Kafka에서는 하나의 Partition에 대해 하나의 Consumer Group 내의 consumer instance만 허용하여 데이터를 순서대로 읽을 수 있도록 보장한다. 이 이론을 먼저 인지하고 난 다음 아래의 예제를 이용하여 어떻게 설계하는지에 대해 생각해보자.

 

 

 

위에서 언급한 결론에 따르면, 하나의 partition에는 하나의 Consumer Group에 할당된 instance만 접근할 수 있다고 하였기 때문에 Consumer B의 경우 유휴상태가 되어 데이터를 처리하지 못한다. 따라서 Consumer A가 비정상이 되었을 때, Consumer B는 제 기능을 하는 standby instance가 된다.

 

 

 

위 그림의 경우도 하나의 Partition에 대해 하나의 Consumer Instance가 연결되어 있다. Consumer Instance가 Partition의 수보다 적기 때문에 하나의 Consumer Instance가 여러개의 Partition Data를 담당하여 번갈아가면서 데이터를 가지고 오게 된다. 이 때, 그림처럼 Consumer B ↔︎ Partition 4의 예기치 못하게 끊기게 되면 대체제인 Consumer A로 붙어 운영이 될 것이다.

 

 

 

실제로는 운영을 하면서 최적의 구성을 찾는 것이 가장 좋지만, 무조건 속도를 고려하게 되었을 때를 가정였을 때 얻은 결론은 결론은 다음과 같다.

  • 병렬처리를 극대화 하기 위해서는 하나의 파티션당 하나의 Consumer Instance가 존재해야한다.
  • 위 상황에서 하나의 Consumer Instance가 장애가 날 경우, 즉시 다른 Consumer Instance를 해당 partition에 할당하여 데이터를 핸들링 할 수 있어야 한다.