191. 컨슈머 그룹 (Consumer Group) - 카프카(Kafka) 부하 분산

⚠️ 이 문서는 초당 수백만 건의 데이터(메시지)가 쏟아지는 아파치 카프카(Apache Kafka) 환경에서, 메시지를 읽어가는 서버(Consumer) 한 대가 감당하지 못하고 터지는 것을 막기 위해, 여러 대의 서버를 하나의 '그룹'으로 묶어 파티션(Partition)을 공평하게 나눠 읽음으로써 극강의 스케일 아웃(Scale-out)과 고가용성을 달성하는 '컨슈머 그룹' 아키텍처를 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 똑같은 일을 하는 복제된 워커 서버 3대를 '결제팀 컨슈머 그룹'이라는 이름표 하나로 묶어주는 논리적인 울타리(Logical Group)다.
  2. 가치: 카프카에 100개의 메시지가 쌓여있을 때, 3대의 서버가 똑같은 100개를 중복해서 3번 처리하는 참사를 막아준다. 컨슈머 그룹으로 묶이면 1번 서버가 33개, 2번 서버가 33개, 3번 서버가 34개를 기가 막히게 쪼개서(Load Balancing) 1번씩만 처리한다.
  3. 기술 체계: 카프카 토픽의 '파티션(Partition) 1개'는 컨슈머 그룹 내의 '컨슈머 1대'와만 독점적으로 1:1 연결된다는 절대 원칙이 파이프라인 성능 튜닝의 핵심이다.

Ⅰ. 단일 컨슈머의 비극: 쏟아지는 물줄기 앞의 종이컵

카프카는 엄청나게 빠르지만, 메시지를 처리하는 앱은 느리다.

  1. 프로듀서(Publisher)와 컨슈머(Consumer)의 속도 차이:
    • 프론트엔드(프로듀서)에서 "고객 가입" 이벤트를 1초에 1만 개씩 카프카 토픽으로 쏟아붓는다.
    • 그런데 이 이벤트를 카프카에서 꺼내어 DB에 INSERT 하고 웰컴 메일을 보내는 '회원 관리 서버(컨슈머)'는 1초에 1,000개밖에 처리하지 못한다.
  2. Lag (지연 현상)의 발생:
    • 컨슈머가 소화하지 못하고 남은 메시지 9,000개는 매초 카프카 토픽에 무섭게 쌓여간다. 이를 **컨슈머 랙(Consumer Lag)**이라 부른다.
    • 이를 해결하기 위해 똑같은 '회원 관리 서버'를 2대 더 복제해서(Scale-out) 총 3대로 늘렸다.
  3. 독립 컨슈머의 중복 처리 문제:
    • 서버 3대를 그냥 켜면, 카프카는 3대 모두에게 각각 1만 개의 가입 이벤트를 몽땅 똑같이 던져버린다.
    • 결국 고객 한 명에게 웰컴 메일이 3통씩 날아가는 끔찍한 버그(중복 처리)가 터진다.

📢 섹션 요약 비유: 공장에서 초당 1만 개의 초콜릿(메시지)이 컨베이어 벨트(카프카)로 쏟아지는데, 포장하는 알바생(단일 컨슈머) 1명은 초당 1천 개밖에 포장하지 못해 초콜릿이 산더미처럼 쌓입니다. 급하게 알바생 2명을 더 불렀더니, 이번엔 3명의 알바생이 똑같은 초콜릿 1개를 잡으려고 서로 싸우다 초콜릿이 으깨져 버리는(중복 처리) 대참사가 일어납니다.


Ⅱ. 컨슈머 그룹의 해결책: 파티션(Partition) 분할 독점

그룹으로 묶는 순간, 카프카는 이들을 하나의 거대한 팀으로 대우한다.

  1. 컨슈머 그룹 (Consumer Group) 아이디 매핑:
    • 3대의 '회원 관리 서버' 코드 설정에 group.id="member-team"이라고 똑같이 적어 넣고 실행한다.
    • 카프카는 이 3대를 'member-team'이라는 하나의 조직으로 인식하고, 똑같은 초콜릿을 주지 않고 공평하게 나누어 배급하기 시작한다.
  2. 파티션 대 컨슈머의 1:N 절대 규칙:
    • 카프카의 토픽은 내부적으로 물리적인 서랍장(Partition) 여러 개로 나뉘어 있다 (예: 파티션 3개).
    • 절대 원칙: "하나의 파티션은 하나의 컨슈머 그룹 안에서 오직 1대의 컨슈머에게만 할당된다."
    • 따라서 파티션 0번은 1번 서버가 독점, 파티션 1번은 2번 서버가 독점, 파티션 2번은 3번 서버가 독점하여 데이터를 읽어 간다. 완벽한 부하 분산(Load Balancing)과 중복 방지가 동시에 해결된다.

📢 섹션 요약 비유: 알바생 3명에게 똑같은 조끼(컨슈머 그룹 ID)를 입혀 "너흰 이제 한 팀이야"라고 선언합니다. 그리고 컨베이어 벨트(토픽)를 3가닥(파티션 3개)으로 쪼갠 뒤, 알바생 1명당 1가닥의 벨트 앞에 서서 그 벨트로 내려오는 초콜릿만 전담해서 포장하게 만듭니다. 아무도 싸우지 않고 일처리가 3배 빨라지는 완벽한 분업 시스템입니다.


Ⅲ. 리밸런싱 (Rebalancing)과 스케일링의 한계

알바생이 화장실에 가면 벨트는 알아서 재분배된다. 하지만 벨트 개수 이상으로 알바생을 뽑을 수는 없다.

  1. 자동 장애 복구 (Rebalancing):
    • 3대의 서버 중 2번 서버가 메모리 부족으로 뻗어버렸다.
    • 카프카 코디네이터는 2번 서버의 심박수(Heartbeat)가 멈춘 것을 감지하고, 즉시 작업을 중지(Stop the world)시킨 뒤, 2번 서버가 맡고 있던 '파티션 1'을 살아있는 1번 또는 3번 서버에게 재할당(Rebalance)해 준다. 단 1건의 데이터도 멈추지 않고 다시 처리가 재개된다.
  2. 가장 흔한 설계 실수: 파티션 개수 < 컨슈머 개수:
    • 트래픽이 또 몰려서 급하게 서버를 4대로 늘렸다(Scale-out).
    • 그런데 토픽의 파티션이 3개뿐이라면? 3개의 파티션은 이미 3대의 서버가 독점하고 있으므로, 새로 투입된 4번째 서버는 파티션을 배정받지 못하고 영원히 빈둥빈둥 놀게 된다(Idle).
    • 결론: 컨슈머(서버)를 아무리 늘려봤자 파티션 개수 이상으로는 절대 속도가 빨라지지 않는다. 트래픽을 대비해 설계 시 파티션을 넉넉히(예: 10개, 50개) 쪼개놓아야 하는 이유다.

📢 섹션 요약 비유: 벨트가 3가닥(파티션 3개)뿐인 공장에 알바생을 4명 고용해 봤자, 4번째 알바생은 잡을 벨트가 없어 구석에서 핸드폰만 보며 월급을 축냅니다. 공장 스피드를 더 올리고 싶다면 알바생을 늘리기 전에 반드시 컨베이어 벨트를 4가닥, 5가닥으로 먼저 공사해서 찢어놔야(파티션 추가) 알바생들이 제 몫을 할 수 있습니다.