Apache Kafka ‐ Kafka 메시지 처리 성능 높이기(병렬 처리) - dnwls16071/Backend_Summary GitHub Wiki

📚 파티션(Partition)

  • 파티션(Partition)은 큐(메시지를 임시로 저장할 수 있는 공간)를 여러개로 늘려서 병렬 처리를 가능하게 하는 기본 단위이다.
  • 파티션은 메시지 처리량에 큰 영향을 미치는 핵심 요인이다. 왜냐하면 메시지를 순차적으로 처리하는 것보다 병렬적으로 처리하는 것이 성능상 이점이 많기 때문이다.

[각 토픽은 하나 이상의 파티션으로 구성된다.]

image
  • 토픽을 생성할 때 별도의 옵션을 주지 않으면 기본적으로 1개의 파티션만 생성된다.
  • 필요하다면 하나의 토픽 안에 여러 파티션을 둘 수 있다.
image

[여러 파티션을 두는 상황이라면 Producer가 특정 토픽에 메시지를 넣을 때 여러 파티션에 메시지가 적절하게 분산된다.]

image

[하나의 파티션은 하나의 컨슈머에게만 할당된다.]

image
  • 하나의 파티션은 동일한 Consumer Group 내에서 단 하나의 컨슈머에게만 할당된다.

[하나의 컨슈머가 여러 파티션을 처리할 수 있다.]

image
  • 여러 컨슈머가 하나의 파티션에 할당될 수 없기 때문에 같이 처리할 수 없으나 하나의 컨슈머가 여러 파티션을 처리하는 것은 가능하다.

📚 특정 토픽 파티션 수 조회/설정/변경 방법

ubuntu@ip-172-31-3-2:~/kafka_2.13-4.0.0$ bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic email.send
Topic: email.send       TopicId: GVTU1J3uSJyxmWCc-CcLnw PartitionCount: 1       ReplicationFactor: 1   Configs: segment.bytes=1073741824
        Topic: email.send       Partition: 0    Leader: 1       Replicas: 1     Isr: 1  Elr:    LastKnownElr: 
Topic: email-send       TopicId: STANS5k1T4-ItFtbonUeHw PartitionCount: 1       ReplicationFactor: 1   Configs: segment.bytes=1073741824
        Topic: email-send       Partition: 0    Leader: 1       Replicas: 1     Isr: 1  Elr:    LastKnownElr:
  • PartitionCount : 토픽이 가지고 있는 파티션 총 개수(기본적으로는 파티션 1개만 생성)
  • Partition : 파티션 번호(0부터 시작)
// bin/kafka-topics.sh --bootstrap-server <kafka 주소> --create --topic <토픽명> --partitions <파티션 수>
// 이 때, localhost라고 쓴 이유는 EC2 내부에서 실행시켰기 때문이다. 만약 인텔리제이 터미널이라면 [EC2 퍼블릭 주소:포트번호]로 접근해야한다.

$ bin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test.topic --partitions 3

Kafka 컨슈머의 파티션 할당 전략

  • Sticky Partition 할당 전략 : Consumer가 구독 중인 Partition을 계속 유지하게끔 할당한다.
  • Round Robin Partition 할당 전략 : 사용 가능한 Partition과 Consumer를 순차적으로 할당한다.
    • Kafka 2.4 Ver 이전 : 라운드 로빈 방식(번갈아가면서 차례대로 하나씩 배분하는 방식)으로 메시지를 분배
    • Kafka 2.4 Ver 이후 : 기본 메시지 분배 방식이 라운드 로빈 방식에서 스티키 파티셔닝 방식으로 변경
spring:
  kafka:
    bootstrap-servers: EC2 Public IPs:Port
      producer:
        key-serializer: org.apache.kafka.common.serialization.StringSerializer
        value-serializer: org.apache.kafka.common.serialization.StringSerializer
        properties:  # Round Robin Partition 할당 전략 적용
          partitioner.class: org.apache.kafka.clients.producer.RoundRobinPartitioner

📚 하나의 컨슈머로 메시지 병렬 처리하기

참고 : 여러 컨슈머로 메시지 병렬 처리하는 것 역시 가능하다.

@KafkaListener(
    topics = "email.send",
    groupId = "email-send-group",
    concurrency = "3" // 멀티 쓰레드를 활용해 병렬적으로 처리할 파티션의 개수
)
image
  • 위와 같이 하나의 컨슈머 그룹 내에서 여러 쓰레드가 만들어지고 하나의 쓰레드가 하나의 파티션에 있는 메시지를 처리하게 된다.
  • 그러나 트레이드오프를 염두에 두고 있어야 한다. 파티션의 수를 무작정 과도하게 늘리게 되면 오히려 반대로 성능 비효율성을 불러온다.
  • 그래서 적절한 파티션 수를 설계하는게 중요하다.

📚 적정 파티션의 개수⭐

  • 적정 파티션 개수를 정할 때 핵심은 처리가 지연되는 메시지가 생기지 않는 선에서 파티션을 최소로 설정하는 것이다.
프로듀서가 보내는 메시지량 ≤ 하나의 쓰레드가 처리하는 메시지량 x 파티션 수
  1. 몇 개의 쓰레드를 사용해야 처리량이 가장 높아지는가를 측정하기 - SpringBoot는 멀티 쓰레드 기반이기 때문에 동시에 여러 요청 처리가 가능하다.
  2. 하나의 컨슈머 서버가 처리할 수 있는 최대 처리량(Throught)을 알아내기 - 컨슈머 서버가 적절한 쓰레드 개수를 기반으로 요청을 처리한다고 가정할 때, 최대 처리량이 얼마나 되는가를 측정해야 한다.
  3. 프로듀서가 보내는 평균 메시지량 알아내기 - 사용자가 API 요청을 얼마나 보내는가와 같은 의미이다.
  4. 처리가 지연되지 않는 선에서 파티션 개수 계산하기 - 처리가 지연되지 않으려면 프로듀서에서 들어오는 메시지 수보다 더 빠르게 처리가 되어야만 한다. 그리고 평균 메시지량이 어느 정도 초과할 것도 예상해서 계산을 해야 한다.

📚 Consumer Lag⭐

  • Lag란, 지연된 메시지 수(=컨슈머가 아직 처리하지 못한 메시지의 수)이다. 다른 말로 Consumer Lag라고 부른다.
  • Consumer Lag는 프로듀서 메시지 생산량을 컨슈머 메시지 처리량이 못 따라가줘서 발생한다.
  • 그렇기 때문에 Consumer Lag를 체크하는 것이 중요한데 체크 방법은 다양하다.
    • 외부 모니터링 툴 사용하기(Datadog, Prometheus, Grafana)
    • Managed Service 사용하기(AWS MSK, Confluent Cloud)
⚠️ **GitHub.com Fallback** ⚠️