Kafka 병렬 처리를 활용한 메세지 처리 성능 높이기

2026. 2. 1. 22:34·🌊 Data Engineering
728x90

오늘도 인프런의 박재성 강사님의 실전에서 바로 써먹는 Kafka 강의와 함께 합니다. 

 

강의를 시작하면서 발견 된 문제는 컨슈머가 메세지를 한번에 하나씩만 처리하게 되어 스프링 부트의 장점을 전혀 못 살리고 있다는 점이었습니다. 이런 문제는 Kafka가 가지고 있는 파티션이라는 개념을 활용해서 병렬 처리를 통해 가능 할 수 있도록 합니다. 

 

파티션이란?

파티션은 Kafka 토픽을 내부적으로 나눈 단위로, 메시지를 여러 줄로 분산 저장해 병렬 처리와 확장성을 가능하게 합니다.
같은 파티션 안에서는 메시지 순서가 보장되며, 서로 다른 파티션은 독립적으로 동시에 처리될 수 있습니다.

 

아래는 GPT가 생성해준 아키텍처 그림입니다.

topic1 하위에 여러 파티션으로 나눠져 있는 것을 확인 할 수 있고, Producer는 적절하게 여러 파티션에 메세지를 분산하여 저장합니다. 또한 하나의 파티션은 하나의 컨슈머 그룹 내의 하나의 컨슈머에게만 할당이 됩니다. 

하지만 하나의 컨슈머는 여러 파티션을 처리 할 수 있고, 컨슈머는 메세지를 순서대로 처리하게 됩니다. 오프셋이 0인 메세지를 다 처리 하고 -> 1로 넘어가도록 순차적으로 한다고 생각하시면 됩니다. 이 때문에 파티션이 1개인 경우 컨슈머가 메세지를 한번에 하나씩만 처리하게 되는 것 입니다.

 

 

 

 

 

 

 

특정 토픽의 파티션 수 조회, 설정, 변경하기

 

진짜 topic을 생성 할 때 파티션은 하나인지 확인해 보기 위해서는 --describe 명령어와 함께 topic에 대한 내용들을 확인 할 수 있습니다. 아래의 문법을 통해서 생성하고 파티션 수를 변경 할 수 있습니다. 

이 때 주의해야 하는 점은 파티션 수는 감소 할 수 없고 (예: 5개에서 3개로 줄이는 건 안됨) 증가 할 수만 있다는 점입니다. 그래서 기존 개수에서 줄여야 하는 경우에는 마이그레이션 작업을 통해서 파티션 개수를 줄이는 작업이 필요합니다. 이 작업은 귀찮기 때문에 처음 파티션 개수를 적절하게 정해주는 것이 필요합니다.

 

# 생성 문법
$ bin/kafka-topics.sh \
	--bootstrap-server <kafka 주소> \
	--create \
	--topic <토픽명> \
	--partitions <파티션 수>
 
# partitions 수 증가 문법
$ bin/kafka-topics.sh \
	--bootstrap-server localhost:9092 \
	--alter \
	--topic test.topic \
	--partitions 5

 

메세지 병렬 처리 방법 확인해보기

 

- 여러 개의 컨슈머로 병렬적으로 처리하기

 

하나의 토픽에 파티션 3개를 생성하고 컨슈머 서버 1개를 할당하고 테스트를 해보았습니다. 컨슈머 서버를 종료했다가 다시 올렸을 때 3개의 파티션이 할당되어 있는 것이 로그로 남아 있는 것을 볼 수 있었습니다. 또 하나의 컨슈머 서버에서는 한 번에 하나의 작업만 진행합니다. 

 

2026-02-01T21:01:33.216+09:00  INFO 13544 --- [email-send-consumer] [ntainer#0-0-C-1] 
k.c.c.i.ConsumerRebalanceListenerInvoker :
[Consumer clientId=consumer-email-send-group-6, groupId=email-send-group] 
Adding newly assigned partitions: [email.send2-0, email.send2-1, email.send2-2]

 

병렬 처리를 위해서는 컨슈머 서버를 하나 더 올리고 분산 처리 할 수 있도록 할 수 있습니다.

하나의 컨슈머 서버의 리소스(CPU, 메모리 등)가 부족한 상태가 아님에도 불구하고 spring boot 서버를 하나 더 올리는 방식은 조금 아쉬움으로 아래에는 하나의 컨슈머를 활용해서 메세지를 병렬적으로 처리 하는 방법을 알아보겠습니다.

 

- 하나의 컨슈머로 병렬적으로 처리하기

 

@RetryableTopic 어노테이션 하위의 concurrency 를 설정하여 멀티 스레드 개수를 지정 할 수 있습니다.

동시에 병렬적으로 처리할 파티션의 개수를 작성하면됩니다. 최대 병렬 처리 할 수 있는 개수는 파티션 수입니다.

 

  @RetryableTopic(
      attempts = "5",
      backOff = @org.springframework.kafka.annotation.BackOff(
          delay = 1000,
          multiplier = 2.0
        ),
      dltTopicSuffix = ".dlt",
      concurrency = "3"
  )

 

 

 

실무에서 여러 토픽을 처리 하는 방법은 크게 2가지입니다.

첫번째는 하나의 컨슈머 서버에서 여러 카프타 리스너를 활용하여 리소스를 활용하고, 관리 포인트를 줄이는 방식으로 사용 할 수 있습니다. 하지만 이 방식은 하나의 토픽에 장애가 발생한 경우 다른 토픽들도 영향을 받을 수 있다는 단점이 있습니다.

 

두번째는 토픽 별로 서비스를 완전히 분리하여 사용하는 것으로 서비스 별로 독립적인 스케일링이 가능하다는 장점을 가집니다. 하지만 운영 복잡도가 증가하고 리소스에 대한 오버헤드가 발생하게 될 수 있습니다. 외부 연동, 장애 특성이 다르거나 팀이 분리 되어 있는 경우 해당 방법을 사용하는 경우가 많습니다. 

 

현재 회사에서는 두번째 방식을 채택하고 있는데요, 장애 영향도를 최소한으로 하기 위해서인 것으로 보입니다. 

 

 

적정 파티션 개수를 계산하는 방법

처리 지연되는 메세지가 생기지 않는 선에서의 파티션 수를 최소로 설정하는 것이 중요합니다.

즉, 컨슈머가 처리 할 수 있는 양(하나의 스레드가 처리하는 메세지 양 * 파티션 수)이 프로듀서가 kafka에게 보내는 메세지 양보다 많으면 됩니다.

 

- 몇 개의 스레드를 활용해야 처리량을 가장 높일 수 있는지 측정하기 (부하 테스트 개념)

- 하나의 컨슈머 서버가 처리할 수 있는 최대 처리량(Throughput) 알아내기

- 프로듀서가 보내는 평균 메세지량 알아내기 (예상 트래픽량 계산해보기)

- 처리가 지연되지 않는 선에서 파티션 개수 계산하기

 

 

Consumer Lag 확인하기

회사에서 Kafka Lag에 대한 이야기를 많이 들었는데 이제 'Lag'이 어떤 것인지 알아보겠습니다.

렉(Lag)은 컨슈머가 아직 처리하지 못한 메세지 수를 의미하며 지연된 메세지 수를 의미합니다.

 

프로듀서의 메세지 생산량이 컨슈머의 메세지 처리량보다 클 때 컨슈머 렉(Consumer Lag)이 발생하게 됩니다. 현업에서는 서비스 운영 시에 갑작스럽게 요청이 증가하거나, 컨슈머 서버에 장애가 생겼을 때 메세지 처리를 잘 못하게 되면서 발생됩니다. 따라서 컨슈머 렉이 늘어나면 빠르게 조치를 취하는 것이 필요하여 모니터링을 지속적으로 하는 것이 필요합니다.

 

다음과 같은 cli 명령어의 Lag 컬럼을 통해 확인 할 수 있습니다.

bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 
--group email-send-group --describe

 

 

현업에서는 외부 모니터링 툴(예: burrow, prometheus/grafana, 데이터독 등)을 이용해서 체크하거나, 직접 카프카를 직접 구축하지 않고 클라우드의 카프카 서비스를 사용한 경우(AWS MSK, Confluent Cloud 등)에는 자체적으로 컨슈머 렉에 대한 모니터링 기능을 같이 제공하는 경우가 많습니다. 

 

요렇게 병렬 처리 하는 방법들을 알아 보았는데요, 다음에는 Kafka 자체에 대한 장애 대비하는 방법, MSA 프로젝트에서 Kafka를 도입하는 방법들에 대해서 알아보겠습니다.

 

(+)

 

추가로 궁금해진 점은 사실 저는 현업에서 java가 아니라 python으로 서버를 구성해서 사용하게 될 것 같은데요. python의 경우에는 단일 스레드 언어로 알고 있는데 멀티 스레드 개념을 가지지 않은 경우에도 파티션의 장점을 가져 갈 수 있는 건지 궁금해졌습니다 ㅇㅅㅇ.

 

GPT야! 부탁해!

 

GPT와 토론 내용을 정리해보면 다음과 같습니다. 

 

한 문장으로 이해하면 Kafka의 병렬성은 “멀티 스레드”가 아니라 “여러 컨슈머(프로세스)가 파티션을 나눠 갖는 구조”에서 나옵니다. 그래서 Java든 Python이든, 파티션 수만큼 컨슈머를 띄우면 동일한 병렬 처리 효과를 얻을 수 있습니다.

 

이라고 합니다. 이전 concurrency 스레드 개수를 활용한 것이 생각나서 해당 개념을 이야기 하면서 말해보니 다음과 같이 말합니다. Python의 경우 replica를 늘리는 방식이 좀 더 많다고 주장하는 것 같은데 회사 아키텍처를 봐보고 좀 더 찾아봐야겠습니다..

 

여기서 포인트는 이거예요.

Spring Kafka의 concurrency = 한 프로세스 안에서 스레드로 컨슈머 수를 늘림 Python에서는 GIL 때문에 CPU 병렬 스레드가 제한될 수 있지만, Kafka 병렬 처리의 핵심은 “컨슈머 수”라서 Python에서는 보통 이렇게 합니다.

프로세스를 여러 개 띄워서(또는 컨테이너/파드 replica 늘려서) 같은 consumer group으로 붙게 만들고 파티션을 나눠 병렬 처리. 즉, Java/Spring은 “스레드(concurrency)로 컨슈머 수를 늘리기”가 편하고, Python은 “프로세스/인스턴스를 늘려 컨슈머 수를 늘리기”가 일반적입니다.

둘 다 결과적으로는 파티션을 나눠 갖는 병렬 처리를 합니다.

 

 

 

300x250
저작자표시 비영리 변경금지 (새창열림)

'🌊 Data Engineering' 카테고리의 다른 글

RabbitMQ 기본 개념 정리 (+ RabbitMQ vs Kafka vs ActiveMQ)  (0) 2026.02.20
Kafka는 어떻게 고가용성을 확보하고 있을까? (feat. 노드, 브로커, 컨트롤러, 클러스터, 래플리케이션)  (0) 2026.02.04
Kafka 기본 개념 정의 및 실패 재시도 방법 정의  (0) 2026.02.01
Apache Airflow 간단 개념 알아보기  (0) 2026.01.31
'🌊 Data Engineering' 카테고리의 다른 글
  • RabbitMQ 기본 개념 정리 (+ RabbitMQ vs Kafka vs ActiveMQ)
  • Kafka는 어떻게 고가용성을 확보하고 있을까? (feat. 노드, 브로커, 컨트롤러, 클러스터, 래플리케이션)
  • Kafka 기본 개념 정의 및 실패 재시도 방법 정의
  • Apache Airflow 간단 개념 알아보기
최밍구
최밍구
발등에 불이 뜨겁게 배우는 중
  • 최밍구
    프로그래밍구
    최밍구
  • 전체
    오늘
    어제
    • 분류 전체보기
      • ☕️ JAVA
      • 🌱 Spring
      • 🐍 Python
      • 🗄️ DataBase
      • 🌊 Data Engineering
      • 🛠️ DevOps
      • ✨ JavaScript
        • Node.js
      • 🤖 AI
      • 🔎 알고리즘
      • 📘 IT 지식
      • 🍀 창고
        • 비트캠프
        • 취업
        • 일기장
  • 링크

    • Go Github
  • 인기 글

  • 태그

    dataengineering
    pgvector
    인터넷
    PostgreSQL
    RabbitMQ
    data
    Java
    생활코딩자바
    타임존
    MSA
    mongoDB
    자바
    데이터베이스
    database
    Airflow
    생활코딩
    카프카
    Kafka
    제네릭
    자바제네릭
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
최밍구
Kafka 병렬 처리를 활용한 메세지 처리 성능 높이기
상단으로

티스토리툴바