카프카(Kafka)란?, 메세지 큐 들여다 보기

정현우·2021년 7월 19일
12
post-thumbnail

대표적인 "이벤트 브로커" 카프카의 원리를 좀 더 자세하게 살펴보자. 메시지 브로커에 역할에 좀 더 집중한다.

메시지 큐(Message Queue)

1. 메시지 브로커 vs 이벤트 브로커

1) 메시지 브로커

  • 메시지 브로커는 publisher가 생산한 메시지를 메시지 큐에 저장하고, 저장된 데이터를 consumer가 가져갈 수 있도록 "중간 다리 역할"을 해주는 브로커(broker)다. 흔히 S/W 관점에서 "미들웨어"라고 한다.

  • 보통 서로 다른 시스템(혹은 소프트웨어 / 이기종간) 사이에서 데이터를 비동기 형태로 처리하기 위해 사용한다.

  • 이러한 구조를 보통 pub/sub 구조라고 하며 대표적으로 RabbitMQ 소프트웨어가 있고 GCP의 pubsub, AWS의 SQS 같은 서비스가 있다.

  • 이와 같은 메시지 브로커들은 consumer가 큐에서 데이터를 가져가게 되면 즉시 혹은 짧은 시간 내에 큐에서 데이터가 삭제되는 특징이 있다.

2) 이벤트 브로커

  • 이벤트 브로커 또한 기본적으로 메시지 브로커의 큐 기능들을 가지고 있어 메시지 브로커의 역할도 할 수 있다. 가장 중요한 차이는 이벤트 브로커는 메시지 브로커 역할을 할 수 있지만, 메시지 브로커는 이벤트 브로커 역할을 할 수 없다.

  • 또한 이벤트 브로커는 publisher가 생산한 이벤트를 저장하여, 후에 consumer가 특정 시점부터 이벤트를 다시 consume 할 수 있는 장점이 있다. (예를 들어 "장애가 일어난 시점부터 그 이후의 이벤트들을 다시 처리" 할 수 있다.)

  • 대용량 데이터 처리에 있어서 메시지 브로커보다는 더 많은 양의 데이터를 처리할 수 있는 능력이 있다.

3) 메시지 큐란?

  • 메시지 큐(Message Queue 이하 MQ)란 프로세스(프로그램) 간에 데이터를 교환할 때 사용하는 통신 방법 중에 하나로 더 큰 개념으로는 MOM(Message Oriented Middleware : 메시지 지향 미들웨어 이하 MOM)를 의미한다. MOM이란 비동기 메시지를 사용하는 프로그램 간의 데이터 송수신을 의미하는데 MOM을 구현한 시스템을 MQ라고 한다. MQ는 작업을 늦출 수 있는 유연성을 제공한다.

  • 사용해야하는 12가지 이유

4) AMQP

  • 메시지를 교환할 때 AMQP(Advanced Message Queuing Protocol 이하 AMQP)을 이용한다. AMQP는 ISO 응용 계층의 MOM 표준으로 JMS(Java Message Service)와 비교되는데 JMS는 MOM를 자바에서 지원하는 표준 API다. JMS는 다른 Java Application 간에 통신은 가능하지만 다른 MOM(AMQP, SMTP 등)끼리는 통신할 수 없다. 그에 반해 AMQP는 protocol만 일치한다면 다른 AMQP를 사용한 Application과도 통신이 가능하다. AMQP는 wire-protocol을 제공하는데 이는 octet stream을 이용해서 다른 네트워크 사이에 데이터를 전송할 수 있는 포맷이다.

5) 메시지 큐의 장점

  1. 비동기 : Queue에 넣기 때문에 나중에 처리할 수 있음.
  2. 비동조 : Application과 분리할 수 있음.
  3. 탄력성 : 일부가 실패 시 전체는 영향을 받지 않는다.
  4. 과잉 : 실패할 경우 재실행이 가능.
  5. 확장성 : 다수의 프로세스들이 큐에 메시지를 보낼 수 있다.

(1) 애플리케이션/시스템 간의 통신

  • 서버 간에 데이터를 주고 받거나 어떤 작업을 요청을 할 때는 항상 시스템 장애를 염두에 두어야 한다. 서버가 갑자기 죽거나 서버 점검 등으로 다운타임이 발생하는 동안에는 요청을 보낼 수가 없다. 요청하는 서버에서 failover 처리를 해놓고 연계 시스템이 다시 살아났을 때 요청을 보내는 방법도 있지만 MQ를 이용하면 더욱 간편하게 처리할 수 있다.

(출처: rabbitmq.com)

  • P는 C에 직접 요청하는 것이 아닌 MQ에 전달한다. 그럼 C는 MQ로 부터 요청 데이터를 수신해서 처리한다. 만약 C가 요청을 받을 수 없을 수 없는 상황이라면 해당 요청은 C가 받을 때까지 MQ에 머무르게 된다.

  • 물론 이런 상황에서 MQ에 다운타임이 발생하면 무용지물이 되어버리겠지만, 많은 MQ가 고가용성을 위해 클러스터링 등을 지원한다.

(2) 서버 부하가 많은 작업

  • 이미지 처리, 비디오 인코딩, 대용량 데이터 처리와 같은 작업은 메모리와 CPU를 많이 사용한다. 이러한 작업은 동시에 처리할 수 있는 양이 상당히 한정적이어서 필요하다고 무작정 요청을 처리할 수는 없다. 이 때에도 MQ를 사용하면 편리한데 처리해야할 작업을 MQ에 넣어두고 서버는 자신이 동시에 처리할 수 있는 양에 따라 하나의 작업이 끝나면 다음에 처리할 작업을 MQ에서 가져와 처리하면 된다.

(3) 부하분산

  • MQ를 통해 부하분산 처리도 가능하다. 지금까지 설명은 하나의 서버에 대해서만 설명했다.

(출처: rabbitmq.com)

  • 그림처럼 여러 대의 서버가 하나의 큐를 바라보도록 구성하면 처리할 데이터가 많아져도 각 서버는 자신의 처리량에 맞게 태스크를 가져와 처리할 수 있다. 이러한 구조는 horizontal scaling에 유리하다.

(4) 데이터 손실 방지

  • MQ를 사용하지 않는다면 외부에서 받은 요청을 메모리에 저장했다가 들어온 순서대로 처리하게 할 수도 있다. 하지만 어떠한 이유로 서버가 다운되어 버리면 메모리에 쌓아둔 요청은 모두 없어지고 만다. MQ를 사용하면 이를 방지할 수 있는데 MQ로부터 가져온 태스크를 일정 시간이 지나도록 처리했다고 다시 MQ에 알려주지 않으면 MQ는 이 태스크를 다시 큐에 넣어 다시 처리할 수 있도록 한다.
  • MQ를 사용할 때 얻을 수 있는 잇점은 많지만 적재적소에 사용해야 한다. 요청 결과를 즉시 응답해야할 때에는 MQ는 어울리지 않는다. 주로 요청과는 별개로 처리할 수 있는 비동기 처리에 어울린다. 또한 서버에서 간단하게 처리할 수 있는 일을 MQ를 통해 전달하면 필요없는 오버헤드될 수도 있다.

6) Linked In 의 kafka 도입 전과 후

  • 도입 전

  • 도입 후


2. MQ 대표 솔루션

1) 다시 살펴보는 5가지 공통 특징

  1. 다른 곳의 API로부터 데이터 송수신
  2. 다양한 Application에서 비동기 통신 가능
  3. 이메일 발송 및 문서 업로드 가능
  4. 많은 양의 프로세스 처리
  5. 메시지 큐 종류

2) 대표적인 종류

  1. Kafka (event broker)
  2. RabbitMQ (message broker)
  3. ActiveMQ (message broker)
  • (메시지 브로커 역할로만 봤을 땐) 성격상 Kafka(Apache)RabbitMQ, ActiveMQ(Apache) 로 나눌 수 있는데 Kafka는 처리량이 많은 분산 메시징 시스템에 적합하고 RabbitMQ, ActiveMQ는 신뢰성 있는 메시지 브로커가 필요한 경우 적합하다. 여기서 신뢰성은 Kafka에 비해 높은 것이지 Kafka가 신뢰성이 없다는 것은 아니다.

  • 3가지 대표적인 차이점 살펴보기


3. 🔥 Apache Kafka

1) 특징

(1) 카프카는 지향하는 바가 다른 메시지 큐와 다르다.

  • 실시간 데이터 피드를 관리하기 위해 통일된 높은 스루풋의 낮은 레이턴시를 지닌 플랫폼을 제공하는것이 목표이다.

(2) pub-sub 구조를 가진다.

  • 메시지를 보내는 역할과 받는 역할이 완벽하게 분리되어 있다.

  • 느슨한 결합을 통해 어느 한쪽 시스템에서 문제가 발생하더라도 서로 의존성이 없으므로 연쇄작용이 발생할 확률은 매우 낮다.

  • 컨슈머의 서버가 하나더 추가 되더라도 카프카로만 보내면 되기 때문에 서버 추가에 대한 부담도 줄일 수 있다.

  • 하나의 토픽에 여러 프로듀서 또는 컨슈머들이 접근 가능한 구조로 되어 있다. 그렇기 때문에 하나의 프로듀서, 컨슈머가 하나의 토픽에만 메시지를 보내는 것이 아니라, 하나 또는 하나 이상의 토픽으로 메시지를 보낼 수, 가져올 수 있다.

(3) 디스크에 메시지를 저장한다.

  • 파티션 파일에 대해서 OS 페이지캐시를 사용한다. -> 파티션에 대한 FILE IO 를 메모리단에서 처리하게 된다. 디스크 버퍼에서 네트워크 버퍼로 직접 데이터 복사하여 처리하게 된다.

  • 다른 message quque 의 가장큰 차이점은 통신할때 TCP/IP통신을 통해 바로 디스크로 쓴다는 점이다. (Rabbit MQ의 경우 APMQ 프로토콜 이용) 다른 MessageQueue도 메모리에만 올리지않고 설정을 통해 서버가 다운되더라도 디스크에 저장하는 설정을 할 수 있다. 카프카는 별도의 설정 없이 디스크에 적재하며, 환경설정에서 그주기를 변경 할 수 있다. 통신방법의 차이로 인해 (TCP/IP, APMQ) 카프카는 초당 10만건, Rabbit MQ는 초당 2만건의 데이터 처리가 가능하다.

  • 별다른 설정 없이도 데이터의 영속성(Persistence)가 보장된다는 것을 의미한다.

  • 트래픽이 일시적으로 폭주해 컨슈머의 처리가 늦어지더라도 카프카의 디스크에 안전하게 보관되어 있기 때문에, 컨슈머는 메시지의 손실 없이 메시지를 가져갈 수 있다.

  • 디스크가 순차적으로 저장되어 있으므로 디스크 I/O가 줄어들어 성능이 빨라진다.

(4) 분산 환경에 특화되도록 설계되었다.

  • 하나의 카프카 클러스터는 3대의 브로커로 부터 시작해 수십대의 브로커로 확장 가능하다.

  • 확장 작업은 카프카 서비스의 중단 없이 온라인 상태에서 작업이 가능하다.

  • 최초 카프카 클러스터 구성시 적은 수로 시작하더라도 이후 트래픽 및 사용량 증가로 클러스터를 확장하는 작업은 매우 간단하고, 큰 부담이 없다.

(5) 클러스터 구성, fail-over , replication 과 같은 여러 특징을 가지고 있다.

  • 카프카는 고성능을 유지하기 위해 내부적으로 분산 처리, 배치 처리 등 다양한 기법을 사용한다.

  • 클러스터 구조의 분산 시스템은 단일 시스템보다 성능이 좋다.

2) 구조와 주요 용어

(1) Topic, Partitions, Offsets

  • topic: 메세지 종류, 특정한 데이터 스트림을 의미한다.

    • 토픽의 개수는 제한이 없고, 이름으로 구분된다.
    • topic이 다시 특정한 개수의 partitions이 된다. 개수의 명시가 필요하다.
  • partitions: topic 이 나눠지는 단위다.

    • 유한한 시간(default oneweek)동안 디스크에 저장되어 있다. 특징 (3)번 참조
    • 파티션에 한 번 쓰여진 데이터는 변경이 불가능 하다.
    • 토픽을 구성하는 파티션은 "정렬"되어 있지만, 쓰여지는 데이터는 키 값이 제공되지 않으면 파티션에 "랜덤하게" 할당된다.
    • 각 파티션 속 메시지는 오름차순의 id값인 offset을 가지고 있다.
  • offsets: 속해 있는 파티션에서만 의미 있는 값, 파티션 내에서 각 메시지가 가지는 unique id

    • 순서는 속해 있는 파티션에서만 보장된다. -> 다른 파티션에서 동일한 offset이 가리키는 데이터는 같지 않다.

(2) Broker

  • broker: 카프카 서버를 가리킨다. 카프카 클러스터는 1개 이상의 브로커(서버)로 구성된다!
    • 각 브로커는 정수형 ID 값으로 구분되며, 특정한 토픽의 파티션을 보유한다.
    • 브로커끼리 연결하면 클러스터가 되며, 3개 이상을 가지는 것이 장애 허용 관점에서 좋다
    • 토픽을 생성하면 카프카가 자동적으로 파티션들을 브로커에 분배한다.

  • 브로커 설명 그림과 같이 분산 처리를 하게 될 때 하나의 브로커에 장애가 발생해도 시스템이 정상적으로 운영되게 하기 위해 다른 브로커에 레플리케이션(복사본)을 만들어두는 것이 안정적이다. 위 그림은 레플리케이션이 3개인 토픽이 브로커가 3개인 클러스터에 각 파티션이 분산되어 있는 예시이다.

  • 토픽은 replication 의 개수가 1개 보다는 커야 좋고, 브로커가 다운되면 다른 브로커가 데이터를 처리해준다.

  • 레플리케이션 정책에서 오직 하나의 브로커만이 주어진 파티션 복사본들의 리더가 될 수 있다. 그리고 오직 이 리더 하나만 데이터를 받고 처리하는 파티션이 된다.

  • 다른 브로커들은 데이터를 동기화한다. 각 파티션은 하나의 리더와 다수의 ISR(In-Sync Replica)이 있다

(3) Producer, Consumer

  • producer: 메세지 생산(발행)자. 기본적으로 kafka에서 프로듀서는 토픽에 데이터를 쓰는 개체이다.
    • producer 는 선택한 topic으로 데이터를 발행한다.
    • producer 는 메세지를 발행할 topic을 선택하는 책임을 제게 된다. 이때 전통적인 round-bin 방식을 사용하여 균등하게 발행 하거나, 메세지 키를 이용하여 특정 partition 에 특정키를 가진 메세지를 보낼수 있다.
    • 어떤 브로커의 파티션에 저장해야하는지 자동으로 저장 위치를 안다. 장애 발생시 자동 회복이 된다. 위 설명과 같이 기본적인 로드 밸런싱이 되어 있다.
    • 메세지에 문자열이나 숫자 등의 키 값을 포함해서 메세지를 보낼 수 있다.
    • 데이터 저장 성공 여부를 acks를 통해 확인할 수 있다.
    • Acks(acknowledgments)

  • 키 값이 없으면 데이터는 라운드 로빈 방식으로 브로커에 전송(로드 밸런싱)

  • 키 값이 있으면 메세지는 (키 해싱에 의한)하나의 파티션에만 지속적으로 전달

  • 특정한 데이터 필드에 대한 요청이 필요하면 키를 활용

  • consumer : 메세지 소비자, 토픽으로부터 데이터를 읽어들인다.

  • 데이터는 각 파티션에 들어온 순서대로 읽힌다.

  • 읽어 들이는 파티션 순서는 정해져 있지 않고, 돌아가면서 병렬처리 된다. -> 파티션 순서에 대한 보장이 없다.

  • consumer group: 개별 컨슈머들을 하나로 묶은 논리적 그룹 단위, consumer 들끼리 메세지를 나눠서 가져간다. offset 을 공유하여 중복으로 가져가지 않는다.

  • 그룹 내 특정 컨슈머에 장애가 생겨도 다른 컨슈머들이 데이터를 읽을 수 있다.

  • 컨슈머 그룹내 컨슈머가 파티션 숫자보다 많으면 비활성화되는 컨슈머가 발생한다. -> 컨슈머와 파티션 개수를 잘 조절해야 한다.

  • 컨슈머 그룹 단위로도 데이터를 읽은 위치 정보인 오프셋이 관리된다. 읽어드린 위치를 기록하는 오프셋은 __consumer_offsets로 관리, 토픽에 저장, 데이터를 읽어드린 순간 오프셋이 기록된다. 컨슈머가 중지되면 오프셋에 저장된 위치에서부터 다시 데이터를 읽어들인다. -> 아래 이미지를 참고하자!

  • 위와 같은 "기록 시점 관련"해서는 아래와 같은 3가지 정책이 있다.

    1) At most once(비선호)
    컨슈머가 메세지를 받는 순간 기록
    처리가 잘못되어도 메세지는 이미 삭제되어 있다(데이터 손실)

    2) At least once(선호)
    메세지를 받은 컨슈머가 데이터를 처리하는 순간 기록
    프로세스가 잘못되면 메세지를 다시 읽어드린다
    데이터 중복 처리가 발생해도 시스템에 문제가 없는 프로세스에만 적용

    3) Exactly once
    카프카 생태계(카프카->카프카)에서 가능(Kafka Stream API 등)
    외부 시스템과의 연결을 할 때는 연산을 여러번해도 결과가 달라지지 않는 컨슈머만 가능(멱등 시스템)

(4) Broker Discovery, Zookeeper

  • 모든 카프카 브로커는 "부트스트랩 서버" 라 불린다.

    • Bootstrap 이란, 일반적으로 한 번 시작되면 알아서 진행되는 일련의 과정을 의미한다.
  • 다른 브로커 하나와만 연결해도 전체 클러스터에 연결이 되며, 각각의 브로커는 전체 브로커와 토픽들 그리고 파티션들에 대한 정보(메타데이터)를 알고 있다.

  • Zookeeper: 카프카 서버 (+클러스터) 상태를 관리 -> 분산 코디네이터다.

    • 브로커를 모니터링하고, 토픽과 파티션을 관리한다.
    • 주키퍼는 카프카 클러스터 내의 브로커들의 리스트를 가지고 있으며 브로커들을 관리하며 카프카는 주키퍼 없이 실행할 수 없다.
    • 리더 파티션에 장애가 발생시 주키퍼를 통해 새로운 리더 파티션을 선발한다.
    • 새로운 토픽 추가, 브로커 장애 및 토픽 삭제 등의 변경 정보를 카프카에 전달한다.
    • 주키퍼는 홀수 개의 서버(3,5,7 ...)를 가지고 있어야 한다.
    • 주키퍼는 쓰기를 관장하는 리더 서버 1개와 읽기를 관장하는 나머지 팔로워 서버로 구성된다

ETC

  • ksql: Kafka를 위한 streaming SQL 이다.
  • kafka topic ui: topic 정보를 확인 할 수 있는 kafaka topic ui
  • ZooNavigator: 주키퍼 정보를 웹으로 네비게이션하고 편집 할 수 있다.
profile
도메인 중심의 개발, 깊이의 가치를 이해하고 “문제 해결” 에 몰두하는 개발자가 되고싶습니다. 그러기 위해 항상 새로운 것에 도전하고 노력하는 개발자가 되고 싶습니다!

0개의 댓글