파티션은 어떻게 컨슈머에게 할당되는가?:

  • 컨슈머 그룹에 참여하고 싶은 첫 번째 컨슈머가 그룹 코디네이터 (= 브로커에서 컨슈머의 멤버를 관리, 컨슈머 상태 관리 등을 해줌) 에게 JoinGroup 요청을 보낸다. 그러면 가장 먼저 참여한 컨슈머가 컨슈머 그룹 리더가 된다. 컨슈머 그룹 리더는 컨슈머 목록 리스트를 바탕으로 파티션을 할당해주는 역할을 한다.
  • 어느 파티션이 어느 컨슈머에게 할당되었는지를 판단할 때 PartitionAssigner 인터페이스 구현체가 사용된다. 파티션 할당 정책은 기본적으로 내장된 몇가지가 있음.
  • 컨슈머 그룹 리더가 새로 들어온 컨슈머나 리밸런싱이 발생할 때마다 파티션 할당 계획을 세우고 이를 그룹 코디네이터에게 전송한다. 그러면 그룹 코디네이터는 이에 맞게 파티션을 컨슈머에게 할당한다.
  • 컨슈머 그룹 리더가 아닌 그룹 코디네이터에서 이 모든 역할을 하면 되지 않는가? 라고 생각할 수 있다. 이렇게 설계한 이유는 여러 작업들을 적절하게 분산시켜서 확장성 있게 설계하려는 목적에 기반함.

 

정적 그룹 멤버쉽:

  • 컨슈머에 group.instance.id 값을 잡아주면 그룹 코디네이터에 이 컨슈머에게 할당된 파티션 정보가 캐싱되게 되면서 컨슈머가 잠깐 동안 이탈하더라도 파티션은 다른 컨슈머에게 재할당되지 않는다.
  • session.timeout.ms 값까지 컨슈머가 그룹 코디네이터에게 하트비트를 보내지 않는다면 그제서야 리밸런싱이 될 것임.

 

스레드 안정성:

  • 하나의 컨슈머에 하나의 스레드가 기본적인 원칙이다. 여러 컨슈머 그룹의 파티션에 하나의 스레드를 사용하거나, 하나의 컨슈머 그룹의 파티션에 여러 스레드를 쓰는 것은 허용되지 않는다.
  • 그래서 어플리케이션에서 여러개의 컨슈머를 사용하고 싶다면 ExecutorSerivce 를 이용해서 여러개의 스레드를 준비해야한다.
  • 또 다른 방법으로는 이벤트를 받아서 큐에 넣는 컨슈머와 큐에서 가지고와서 처리하는 워커 스레드를 준비해서 처리하는 방법도 있다. 이렇게 할 경우에 TCP 레벨에서 더 많은 데이터를 수신할 수 있게된다. TCP 는 Congestion Control 에 의해서 송신 버퍼가 수신 버퍼를 압도하는 경우에 수신 버퍼는 받을 수 있는 데이터의 Window Size 를 송신자에게 더 작은 값으로 보내게 되는데 이러면 네트워크를 통한 데이터 수신이 그만큼 느려지게 된다.
  • https://www.confluent.io/blog/kafka-consumer-multi-threaded-messaging/

+ Recent posts