DevOps

왜 kafka인가요?

권기준 2024. 10. 27. 23:29

서론

 사내 서비스 운영에 kafka 도입이 추진 및 진행되고 있으며, 일부 적용된 상태로 운영 중이다. 사내 서비스 아키텍처를 MSA로 전환하면서 여러모로 이벤트 드리븐 아키텍처의 도입 필요성을 느끼게 되었고, 메시지 브로커의 역할을 할 시스템을 kafka로 선정하게 되었다.
 
 이 점에 대해 이력서에 많이 강조했기 때문일까, 얼마 전 모 기업과 인터뷰를 진행하면서 kafka에 대한 질문을 많이 받았다. 그중 가장 애매한 답변을 내놓게 된 질문이 있었는데, 바로 "왜 kafka인가요?" 였다.
 
 필자는 kafka에 대한 장점을 나열하는 식으로 답변했다. 메시지의 보존, 고가용성 및 확장성 등의 이유를 들며 kafka를 선택한 이유에 대한 열변을 토했다. 하지만, 천천히 복기해 보니 왜 kafka여야 하는가에 대한 근본적인 답변이 되지는 못한 듯했다. 메시지는 컨슈밍 혹은 프로듀싱하는 측에서 보존하면 되는 것 아닌가? 확장성은 RabbitMQ, SQS 등의 서비스도 충분히 제공해주지 않는가?
 
 오늘 포스트에선 kafka가 가지는 장점과 단점에 대해 나열해 본 후, 다른 메시지 큐의 장단점을 비교해 보는 과정을 거치려 한다. 왜 kafka를 브로커 역할로 선택하게 되었는지 복기하는 것이 목표다. 이벤트 드리븐 아키텍처를 도입하려는 분들이 이 글을 보고 kafka를 선택하는 것에 대한 당위성을 얻어갔으면 한다.
 

kafka란?

 kafka는 오픈소스 분산 이벤트 스트리밍 플랫폼이란 거창한 키워드로 소개되고 있다. 이벤트 스트리밍은 각 이벤트 소스에서 만들어지는 특정한 데이터를 캡처하여 스트림 형식으로 제공해 주는 형태로, kafka는 이벤트 스트림을 각 소스에서 발행(publish)하고 구독(subscirbe)할 수 있도록 도와준다.
 

 kafka는 이벤트의 종류를 Topic이라는 개념을 통해 관리하며, Topic은 Partition으로 분리된다. Partition을 여러 개 둠으로써 kafka는 이벤트 스트림을 병렬로 처리할 수 있어, 데이터 처리 속도와 확장성 측면에서 큰 이점이 있다. 또한, 각 Partition은 여러 브로커에 분산 저장되며, 이를 통해 데이터의 고가용성과 내결함성이 보장된다.

 

 kafka의 주요 구성 요소는 크게 Producer, Consumer, Broker로 나뉜다. Producer는 이벤트를 생성하여 특정 Topic에 데이터를 발행(publish)하고, Consumer는 구독(subscribe)한 Topic으로부터 데이터를 받아 처리한다. Broker는 Topic과 Partition을 저장하는, 인스턴스의 개념으로 이해하면 된다.

 

kafka는 빠르다

[출처 : https://www.confluent.io/ko-kr/blog/kafka-fastest-messaging-system/]

 
 kafka는 여타 메시지 큐에 비해 탁월히 높은 처리량(Throughput)을 보유하고 있다. 이는 kafka가 메시지 I/O를 최적화한 메커니즘과 관련이 있다.

 

zero-copy가 적용되기 전과 적용된 후의 비교 [출처: https://blog.bytebytego.com/p/why-is-kafka-fast]

 

 kafka는 zero-copy 메커니즘을 통해 메시지를 디스크에서 네트워크로 전송할 때 추가적인 복사를 줄여 성능을 크게 개선한다. 데이터를 디스크에서 OS Buffer로 로드한 후, 바로 NIC(Network Interface Card) Buffer로 복사하여 커널을 거치지 않도록 한다. 일반적으로 데이터가 디스크에서 메모리로, 메모리에서 네트워크로 복사되는 과정에서 오버헤드가 발생하지만, kafka는 불필요한 복사 단계를 제거함으로써 처리량을 극대화할 수 있었다.

 

 또한, kafka는 데이터를 읽고 저장할 때 Sequential I/O를 활용한다. 데이터를 연속적으로 저장하며, 저장된 순서로 읽기 때문에 자연스레 연속적인 읽기가 가능해진다. Sequential I/O가 Random I/O에 비해 가지는 성능적 이점에 대해선 관련 아티클이 많이 나와있으니, 궁금한 분들은 검색을 통해 알아가셨으면 한다.

 

kafka는 확장 가능하다

카프카 아키텍처 [출처: https://medium.com/@cobch7/kafka-architecture-43333849e0f4]

 

 kafka는 확장성 측면에서 특히 강점을 보인다. 일반적으로 많은 메시지 큐 시스템들은 수평 확장에 제약이 있지만, kafka는 Broker, Topic, Partition이라는 개념을 통해 대규모 데이터 처리에 유연하게 대응할 수 있다.

 Broker는 kafka 클러스터에서 메시지를 저장하고 관리하는 서버를 의미한다. kafka는 클러스터링을 지원하기 때문에 여러 대의 브로커를 구성해 하나의 클러스터로 묶을 수 있다. 이렇게 구성된 클러스터는 각 브로커에 데이터를 분산해 저장함으로써 처리 성능을 높일 수 있고, 특정 브로커에 장애가 발생해도 다른 브로커가 대체하여 안정성을 유지할 수 있다.

 Topic은 kafka에서 데이터를 구분하여 관리하기 위한 개념으로, 데이터를 논리적으로 나눈 그룹이다. Consumer는 특정 토픽을 구독해 해당 데이터를 가져올 수 있기 때문에, 각 토픽에 맞는 데이터를 소비하는 시스템으로 효과적으로 전달할 수 있다.

 Partition각 토픽을 분할한 단위로, 데이터를 더욱 세분화하여 저장한다. 각 Topic이 여러 개의 Partition으로 나뉘어 저장되기 때문에 여러 파티션이 병렬적으로 데이터를 처리할 수 있다. kafka는 이러한 Partition 구조 덕분에 매우 유연한 확장이 가능하며, 데이터 처리량에 한계를 보이는 경우 Partition 수를 추가해 더 많은 데이터를 안정적으로 처리할 수 있다.

 

kafka는 순서를 보장한다

 kafka가 이벤트 순서를 보장한다는 점도 주요 장점 중 하나이다. 정확히는 Topic 내 모든 이벤트의 순서는 보장되지 않지만, Partition 내 이벤트는 순서가 보장된다.

 

 kafka는 이벤트를 발행할 때 특정 Key를 부착할 수 있는데, 같은 Key의 이벤트는 같은 Partition에 발행됨이 보장되므로, 이벤트 순서를 일관되게 유지할 수 있도록 해준다. 이로 인해 주문형 데이터 처리, 로그 분석, 실시간 트랜잭션 처리와 같은 분야에서 데이터의 일관성을 유지할 수 있는 것이 큰 강점이다.

 

 다만, Partition이 증가하게 되면 Key가 같아도 다른 Partition으로 배정될 수 있음은 주의해야 한다.

 

여러 브로커와의 비교

RabbitMQ

kafka 도입 이전에는 사내 다양한 서비스에서 RabbitMQ를 메시지 큐로 사용하고 있었다. RabbitMQ는 설치와 관리가 비교적 쉬운 편이며, 기본적인 몇 가지 프로토콜과 주요 개념만 숙지하면 쉽게 활용할 수 있었다.

 

 RabbitMQ의 가장 큰 장점은 라우팅이 매우 유연하다는 점이다. RabbitMQ는 다양한 exchange 방식을 통한 Multiple Queue로의 메시지 전달이 용이하며, 특정 조건에 따라 메시지를 필터링하거나 복제하는 등 다양한 형태의 라우팅이 가능하다. 즉, 브로커를 복잡한 형태로 사용해야 하는 환경에 매우 유리하다.

 

 또한, RabbitMQ는 Consuming의 성공 및 실패 여부에 대한 처리가 가능하다. 메시지 처리를 컨슈머 단의 이슈로 인해 실패한 경우에도, ack, nack 메커니즘을 통해 다시 메시지를 선택적으로 소비하지 않을 수 있다.

 

 다만, RabbitMQ를 사용하면서 가장 아쉬웠던 부분은 메시지의 영속성에 관한 부분이었다. RabbitMQ는 영속성 설정을 On해도 메시지가 소비되는 순간 디스크에서 사라지기 때문에, 유실에 대한 이슈 트래킹을 하기 어려운 면이 있다.

동일 스펙일 때의 두 시스템 간 메시지 처리량 비교 (https://www.simplilearn.com/kafka-vs-rabbitmq-article)

 

 또한, 대용량 데이터 스트림 처리에 있어 성능이나 확장성 측면의 한계 때문에 Rabbit MQ가 아닌 kafka 도입을 고려하게 되었다. 위에서도 설명한 Sequncial I/O, zero-copy 등의 메커니즘은 kafka와 여타 큐 간의 성능 차이를 발생시키는 원인이다.

 

Redis Stream

 Redis Stream도 고려한 메시지 큐 중 하나였다. Redis Stream은 Redis 데이터 구조의 일종이기 때문에 매우 높은 처리 속도를 제공하지만, 메시지 영속성이나 데이터 복제, 클러스터 확장에 있어서 kafka만큼의 강점은 없다. Redis는 메모리 기반의 저장 구조 덕분에 낮은 지연 시간과 빠른 속도를 제공하는 반면, 메시지가 메모리에 저장되는 특성상 대규모 메시지 보관 및 처리에는 적합하지 않다.

 

 무엇보다, Redis Stream은 Spring Boot 등 다양한 WAS Framework와의 연동성이 떨어진다. 직접 구현해줘야 하는 부분이 다수 있으며, PSA를 충족하지 못해 @KafkaListener, @RabbitListener와 같이 어노테이션을 부착하여 손쉽게 사용할 수 있는 환경이 없다. 아무래도, 사용하는 사람이 많이 없어서인 것 같다.

 

Amazon SQS

 Amazon SQS는 관리형 서비스로써, 간편하게 구축할 수 있다는 장점이 있다. 서버에 대한 물리적 관리가 필요하지 않으며, 높은 가용성과 메시지 영속성을 보장해 준다. 그러나 SQS는 메시지 처리 순서 보장이 되지 않고, 확장성 면에서 kafka만큼 유연하지 않다.

 

마치며

 이렇게 kafka의 강점과, 다른 브로커 간의 비교를 진행해 보았다. 최근 많은 기업에서 kafka를 브로커로써 사용하는 데에는 분명한 이유가 있으며, 이번 글을 통해 그 이유에 대해 명확히 정리할 수 있었다.

 

 이 글이 kafka 도입을 고민하고 있는 많은 분들에게 도움이 되었으면 하는 마음으로, 글을 마쳐보도록 하겠다.

 

참조

1. Kafka Documentation (https://kafka.apache.org/documentation/#intro_streaming)
2. Kafka Vs RabbitMQ: Key Differences & Features Explained (https://www.simplilearn.com/kafka-vs-rabbitmq-article)

3. Apache Kafka Perfomernce (https://developer.confluent.io/learn/kafka-performance/)
4. [Kafka] Kafka가 빠른 이유 (https://ssnotebook.tistory.com/entry/Kafka-Kafka%EA%B0%80-%EB%B9%A0%EB%A5%B8-%EC%9D%B4%EC%9C%A0)

5. Why is Kafka fast? (https://blog.bytebytego.com/p/why-is-kafka-fast)

6. 그웬 샤피라 외 4명 저, 『카프카 핵심 가이드』, 제이펍 (2023)