Apache Kafka ‐ Kafka 메시지 처리 성능 높이기(병렬 처리) - dnwls16071/Backend_Summary GitHub Wiki
- 파티션(Partition)은 큐(메시지를 임시로 저장할 수 있는 공간)를 여러개로 늘려서 병렬 처리를 가능하게 하는 기본 단위이다.
- 파티션은 메시지 처리량에 큰 영향을 미치는 핵심 요인이다. 왜냐하면 메시지를 순차적으로 처리하는 것보다 병렬적으로 처리하는 것이 성능상 이점이 많기 때문이다.
- 토픽을 생성할 때 별도의 옵션을 주지 않으면 기본적으로 1개의 파티션만 생성된다.
- 필요하다면 하나의 토픽 안에 여러 파티션을 둘 수 있다.
- 하나의 파티션은 동일한 Consumer Group 내에서 단 하나의 컨슈머에게만 할당된다.
- 여러 컨슈머가 하나의 파티션에 할당될 수 없기 때문에 같이 처리할 수 없으나 하나의 컨슈머가 여러 파티션을 처리하는 것은 가능하다.
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- 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" // 멀티 쓰레드를 활용해 병렬적으로 처리할 파티션의 개수
)
- 위와 같이 하나의 컨슈머 그룹 내에서 여러 쓰레드가 만들어지고 하나의 쓰레드가 하나의 파티션에 있는 메시지를 처리하게 된다.
- 그러나 트레이드오프를 염두에 두고 있어야 한다. 파티션의 수를 무작정 과도하게 늘리게 되면 오히려 반대로 성능 비효율성을 불러온다.
- 그래서 적절한 파티션 수를 설계하는게 중요하다.
- 적정 파티션 개수를 정할 때 핵심은 처리가 지연되는 메시지가 생기지 않는 선에서 파티션을 최소로 설정하는 것이다.
프로듀서가 보내는 메시지량 ≤ 하나의 쓰레드가 처리하는 메시지량 x 파티션 수
- 몇 개의 쓰레드를 사용해야 처리량이 가장 높아지는가를 측정하기 - SpringBoot는 멀티 쓰레드 기반이기 때문에 동시에 여러 요청 처리가 가능하다.
- 하나의 컨슈머 서버가 처리할 수 있는 최대 처리량(Throught)을 알아내기 - 컨슈머 서버가 적절한 쓰레드 개수를 기반으로 요청을 처리한다고 가정할 때, 최대 처리량이 얼마나 되는가를 측정해야 한다.
- 프로듀서가 보내는 평균 메시지량 알아내기 - 사용자가 API 요청을 얼마나 보내는가와 같은 의미이다.
- 처리가 지연되지 않는 선에서 파티션 개수 계산하기 - 처리가 지연되지 않으려면 프로듀서에서 들어오는 메시지 수보다 더 빠르게 처리가 되어야만 한다. 그리고 평균 메시지량이 어느 정도 초과할 것도 예상해서 계산을 해야 한다.
- Lag란, 지연된 메시지 수(=컨슈머가 아직 처리하지 못한 메시지의 수)이다. 다른 말로 Consumer Lag라고 부른다.
- Consumer Lag는 프로듀서 메시지 생산량을 컨슈머 메시지 처리량이 못 따라가줘서 발생한다.
- 그렇기 때문에 Consumer Lag를 체크하는 것이 중요한데 체크 방법은 다양하다.
- 외부 모니터링 툴 사용하기(Datadog, Prometheus, Grafana)
- Managed Service 사용하기(AWS MSK, Confluent Cloud)