[Kafka] Apache Kafka는 무엇이고 왜 성능이 빠를까?

반응형

카프카란 무엇일까? 카프카란 말을 들어본 적은 있지만 아직 사용해본 적이 없다면 이 소프트웨어가 되게 생소할 수 있습니다. 카프카는 Linkedin에서 처음 개발하여 아파치 오픈 소스까지 오게 된 대용량 메시지 분산 처리 플랫폼입니다.

 

 

 

메시지 분산 처리 플랫폼

여기서 이야기하는 메시지란, 우리가 개발한 일련의 소프트웨어를 통신하기 위한 메시지를 말합니다. 가령 우리는 소프트웨어를 개발할 때 서로 기능을 분리하기 위해 함수를 사용하는데, 함수끼리 통신을 위해서 보내고 받는 데이터들을 정의합니다. 이를 우리는 파라미터라고 합니다.

 

그런데, 마이크로서비스는 어떨까요? 서로 프로세스도 다르고 인스턴스도 다른 상황에서 각 서비스끼리 통신하려면 메시지를 주고 받을 수 있어야 합니다. 이를 위해 우리는 메시지 큐를 사용합니다.

 

  • Mosquitto
  • Redis Pub/Sub

 

메시지 큐는 상대 서비스에서 메시지를 확실하게 받을 수 있도록 보증하며 그렇지 않는 동안에는 자신이 메시지를 가지는 형태입니다. 

 

Kafka는 이런 시스템을 기반으로 하여 더 많고, 더 방대한 데이터를 빠르게 처리할 수 있는 분산 처리 플랫폼입니다. 

 

우리가 마이크로서비스를 구성하다보면 수십, 수백개의 서비스간 통신이 발생합니다. 하나의 서비스에서 많은 메시지를 주고 받을텐데, 이것이 수백개로 많아지면 분산하여 처리해야 하는데, 이에 적합한 소프트웨어가 바로 카프카입니다.

 

 

 

Kafka Architecture

일반적인 메시지 큐는 메시지를 발행하는 Producer(Source)와 메시지를 구독하는 Consumer(Target), 그리고 MQ로 구성되어집니다.

 

 

하지만 Kafka는 분산 처리이기 때문에 다량의 메시지를 받을 Consumer Group과 그들 그룹이 분산하여 메시지를 받을 수 있는 파티션 등 일반적인 메시지 큐보다 좀 더 구성이 풍부합니다.

 

  • Producer: Kafka로 메시지를 보내는 역할 인스턴스
  • Consumer: Kafka에서 메시지를 가져가는 역할 인스턴스
  • Message: Producer를 통해 보내고, Consumer가 읽어가는 데이터 조각
  • Topic: 데이터의 개념적 분리 단위, Producer와 Consumer가 통신하는 하나의 채널
  • Broker: 
    - Kafka 애플리케이션 인스턴스 
    - Topic을 서빙하는 하나의 주체
    - 여러 개의 Broker가 하나의 topic을 서빙할 수 있음(고가용성)
    - 하나의 Broker가 여러 topic을 서빙할 수 있음
    - 하나의 topic이 여러 Broker에 서빙될 수 있음

  • Partitions: 
    - 병렬 처리 및 고성능을 얻기 위해 하나의 토픽을 여러개로 나눈 것
    - topic이 파티션에 나눠지는 형태, 따라서 topic을 파티션의 그룹이라고 할 수 있음
    - 실제로 디스크에 어떻게 저장되는지를 가르는 기준 -> 디스크에는 파티션 단위로 저장됨.
    - Message는 topic 내 어떤 파티션에 저장되어 있음

  • Offset: Message는 파티션 내 순서대로 저장되는데, 여기서 순서가 offset
  • Zookeeper: Kafka 메타데이터 관리 및 Broker Healthcheck 등을 담당
  • Segment: Producer가 전송한 실제 메시지가 Broker의 로컬 디스크에 저장되는 파일

 

 

Kafka의 특성

구조만 보기에는 카프카가 대용량 메시지를 처리하기에 충분한지 파악이 어렵습니다. 카프카의 특성을 보며 대용량 처리에 어떤 핵심적인 역할이 있는지 알아보겠습니다.

 

 

분산 시스템

카프카는 분산 시스템입니다. 여기서 분산 시스템이란, 네트워크 상에 연결된 컴퓨터 그룹을 말하며 하나의 마스터 컴퓨터로 여러개의 컴퓨터를 마치 하나의 컴퓨터처럼 사용하는 시스템입니다.

 

따라서 아래와 같은 장점을 지닙니다.

 

  • 단일 시스템에 비해 처리/반응 속도가 빠름
  • 장애 대응 유리 (하나의 노드에서 오류가 나도 다른 노드에서 대응)
  • 시스템 확장 용이

 

단일 시스템에서는 하나의 시스템에서 모든 메시지를 다 처리하기 때문에 그 한계가 있습니다. 하지만 분산 시스템을 이용하면 하나의 시스템에서 처리할 것을 여러개로 나눠서 처리하기 때문에 처리 속도가 빨라지고 한 번 구축해놓으면 N개 이상 확장하기 쉽습니다.

 

 

페이지 캐시

데이터를 읽고 쓸 때 가장 많이 들어가는 비용은 I/O 작업입니다. 카프카는 Producer로부터 받은 메시지를 저장하는데, 이 때 사용하는 것이 바로 디스크입니다. 어? 그런데, 디스크는 느리잖아요?

 

그렇습니다. 디스크는 메모리에 비해 느립니다. 그래서 카프카는 이러한 디스크의 단점을 극복하기 위해 페이지 캐시를 사용합니다.

 

페이지 캐시란, Disk I/O 성능 향상을 위해 만들어진 메모리 영역으로 한 번 읽은 데이터를 메모리에 저장해두었다가 다시 불러올 때는 Disk가 아닌 메모리에서 불러오기 위해 사용합니다.

 

  • Kafka는 OS가 제공하는 페이지 캐시를 활용
  • 사용하지 않는 일부 메모리를 활용해 Disk I/O에 대한 접근을 줄여 성능 향상

 

특히 후자의 특성 때문에 Kafka에서는 JVM Heap 크기를 5GB로 권장하고 있으며 가급적 Kafka 서버 위에 다른 애플리케이션을 올리지 않습니다. 남는 메모리를 페이지 캐시로 사용하기 위함입니다.

 

 

Zero copy

Linux OS를 공부해보신 분들이라면 이 용어에 대해 익숙할 것입니다. 카프카는 Zero copy를 사용하는데, 앞서 카프카는 디스크 기반으로 동작하여 메시지를 메모리에 애플리케이션 메모리에 올려 보내는 것이 아니라 바로 디스크에 저장해 보내는 방식을 사용합니다.

 

이 때 Disk I/O가 자주 발생하기 때문에 위의 페이지 캐시를 이용해서 이전에 받은 데이터는 Disk I/O를 발생시키지 않고 바로 주고 받는 것이죠.

 

전통적인 데이터 전송 방식은 보통 애플리케이션이 사용하는 메모리 영역에 데이터를 올린 후 전송합니다.

 

Zero copy는 Linux Kernel 함수 중 sendFile 함수를 통해 작동합니다. 

여기서 sendFile은 애플리케이션이 사용하는 메모리에 데이터를 올리지 않고 바로 네트워크에 전송하게 되는데, Kafka는 이 함수를 사용하여 데이터를 전송하여 I/O를 줄여 빠른 속도를 낼 수 있는 것입니다.

 

 

배치/압축 전송

TCP 통신의 단점은 한 번 전송할 때 3 hand shake, 4 hand shake 등 많은 과정을 거치기 때문에 가급적 많은 데이터의 전송은 작게 여러번 보내는 것이 아닌 묶어서 한 번에 보내는 것이 오버헤드가 적습니다.

 

카프카는 묶어서 보내고, 묶어서 받는 배치 전송하기 때문에 이러한 오버헤드를 최소화 하며 성능을 보증합니다.

 

또한 압축 전송을 통해 메시지의 크기를 줄이면서 네트워크 비용도 절약합니다.

 

  • 메시지 전송시 높은 압축 전송을 권장
  • 압축을 통해 네트워크 대역폭(bandwith) 축소

 

여기서 네트워크 대역폭이란, 네트워크가 단위 시간 내 전달할 수 있는 최대 크기의 전달 용량을 의미하는데 대역폭이 크면 클수록 비용이 증가하기 때문에 적은 대역폭을 사용해 네트워크 비용을 줄인 것입니다.

 

 

고가용성 보장

리플리케이션으로 분산 처리함으로써 고가용성을 보장합니다.

 

 

 

Kafka의 Low Latency I/O

아무리 Zero copy, 페이지 캐시를 사용해도 Disk I/O 발생으로 인한 근본적인 성능 이슈는 피할 수 없습니다. 따라서 카프카는 Disk I/O의 성능을 최대한으로 끌어올리기 위해서 카프카는 Sequential I/O를 사용합니다.

 

  • 순차적 데이터 저장을 통해 읽기 지연 감소

 

우리가 표준으로 말하는 디스크의 읽기 속도는 실제 디스크가 데이터를 읽는 속도가 아니라 데이터의 위치를 찾는 시간(seek time)에 의해 디스크 읽기 속도가 지연됩니다. 이러한 이슈가 발생하는 원인은 순차적으로 데이터를 저장하지 않고 랜덤하게 데이터를 저장하는 데 있습니다.

 

카프카는 데이터를 순차적으로 저장하여 이러한 Seek Time이 없습니다.

그런데, 파일을 쓰는 위치는 OS가 결정해줄텐데, 이걸 카프카가 어떻게 제어하는걸까요?

 

카프카는 거대한 파일들(각 default: 1GB)로 저장하는데, 실제로 메시지 하나가 1GB인 것이 아닌 해당 파일 하나에 메시지를 보관하여 모든 메시지가 expire 되었을 때 해당 파일을 삭제합니다.

 

결국 카프카는 100% 완벽한 Sequential I/O를 발생시키는 것이 아니라 미리 거대한 파일 사이즈를 한 개 잡고 거기서 line by line으로 저장하여 I/O 성능을 높이는 것입니다. 따라서 100%가 아닌 8~90% 정도의 순차적 I/O를 발생시키는 것이죠.

 

이러한 부분이 있어 아래와 같은 제약이 따릅니다.

 

  • 가급적 다른 앱이 영향을 주지 않는 독립적인 파일 시스템 사용 권장.
  • 데이터 사이즈가 큰 메시지의 전송은 지양

 

만약 이러한 상황에서, 다른 앱에 의해 I/O가 발생하고 파편화가 생기면 카프카에도 그 영향을 미치게 되며 또한, 데이터 사이즈가 큰 메시지가 대량으로 전송된다면 카프카 단독으로도 디스크 파편화가 발생하기 때문에 가급적이면 데이터 사이즈를 줄이는 게 성능을 보장할 수 있습니다.

 

 

 

마치며…

여기까지 간단하게 Kafka에 대해서 정리해봤습니다. 카프카는 대규모 분산 메시지 처리 플랫폼으로써 기존의 메시지 큐가 가지고 있었던 단점과 비용을 줄이면서 효율적으로 메시지를 처리할 수 있는 훌륭한 소프트웨어입니다.

 

다음 포스트에서는 카프카의 코디네이터인 Zookeeper에 대해서 작성해보겠습니다.

 

반응형

Tistory Comments 0