Skip to main content

[Kafka] Chapter03. 카프카 디자인

· 21 min read
Jeonghun Kong

개요

이번 장에서는 카프카가 어떻게 디자인 되어있는지를 학습할 것이다.
카프카 디자인의 특징인 카프카의 분산 시스템과 페이지 캐시, 배치 처리를 알아 보고 카프카의 데이터 모델에서 토픽과 파티션, 오프셋을 이해하며, 카프카의 고가용성과 리플리케이션을 학습할 것이다.
또한 카프카 운영에 도움을 주는 주키퍼의 지노드 역할을 알아보고 학습을 마무리 할 것이다.

카프카 디자인의 특징

분산 시스템

카프카는 기본적으로 분산 처리 기법이 적용되어있다.
서비스의 확장을 위해 물리적으로 서버를 증설하는 경우, 서비스 애플리케이션을 복제해 실행하는 경우에는 비용이 크고 과정이 쉽지 않다.
허나 카프카는 기본적으로 분산 처리 시스템이기 때문에 클러스터의 브로커를 서버 상황에 따라 유동적으로 확장할 수 있다.

페이지 캐시

카프카의 처리 기능을 높이기 위한 기능중 하나는 페이지 캐싱을 이용하는 것이다.
OS의 캐시 기법인 페이지 캐싱은 메모리의 남은 영역을 이용해 디스크에 바로 읽고 쓰지 않고 데이터를 읽고 쓰는 기법으로 빠른 데이터의 접근을 위해 카프카는 이런 방식을 사용하고 있다.
이 덕분에 카프카를 운용할 서버의 디스크는 저렴한 SATA 디스크를 사용해도 무리가 없다고 한다.

배치 전송 처리

서버와 클라이언트 사이에 데이터를 주고받으면서 크고 작은 I/O가 발생하는 것은 피할 수 없다. 그러나 작은 I/O가 여러번 발생하게된다면 이는 시스템의 성능 저하로 이어질 것이다.
카프카는 이를 피하기 위해 작은 메시지들을 모아서 한번에 처리할 수 있는 배치 전송 처리를 사용하고 있다. 이 덕분에 네트워크 오버헤드 등을 줄이게 되어 높은 성능을 유지할 수 있다.

캬프카 데이터 모델

카프카가 고성능 메세징 애플리케이션으로 발전한 데는 토픽 (Topic)과 파티션 (Partition)이라는 데이터 모델의 역할이 크다.
토픽은 메세지를 받을 수 있는 논리적 묶음고, 파티션은 토픽을 구성하는 데이터 저장소로서 수평 확장이 가능한 단위이다.

Topic

카프카가 메시지를 저장하는 공간이다.
기존의 메일 시스템과 비교하면, 토픽은 메일 주소에 해당한다. 프로듀서는 메세지를 보낼때 토픽에만 보내고, 컨슈머는 메시지를 사용할 때 필요한 토픽에서 가져온다.

토픽은 249자 미만으로 영문, 숫자, '.,_-'를 조합하여 자유롭게 이름을 지을 수 있다.
토픽의 이름은 이후의 시스템 확장을 고려해, 각자 형식에 맞춰 이름을 구분해두는 것이 좋다.
별도의 규칙은 없지만, 최소한의 접두어로 구분해 두는 것을 추천한다.

Partition

카프카의 파티션이란 토픽을 수평 분할한 것이다.

토픽에 전송하는 시간이 1초 걸린다고 가정하자.
이 때, 4개의 프로듀서에서 각각 카프카로 1개의 메시지를 보낸다면, 순차적으로 처리하기 때문에 오롯이 4초가 소요된다. 그러나 파티션을 사용한다면 이를 효과적으로 처리할 수 있다.
하나의 토픽을 4개의 파티션으로 분할한다면, 이 토픽을 사용하는 4개의 프로듀서가 동시에 메세지를 보내도, 모두 1초에 처리할 수 있게 된다.

그러나 여기에 한 가지 제약 사항이 있다.
카프카는 메세징 큐 기반이기 때문에 메세지를 처리하기 위해서는 메세지의 순서가 보장되어야 한다.
이 때문에 앞서 예로 든 1개의 파티션의 경우에서 4초가 소요되는 것이다.

따라서 카프카의 성능을 효율적으로 활용하기 위해서 토픽의 파티션 수와, 해당 토픽을 사용하는 프로듀서/컨슈머의 수를 같게 하는 것이 좋다.

여기서 또 고려 사항이 발생한다. 무조건 파티션의 수를 늘려야하나?
결론을 먼저 언급하자면, 그렇지 않다.

각 파티션은 브로커의 디렉토리와 매핑되고, 데이터 마다 2개의 파일 (인덱스, 실제 데이터)을 저장하게 된다.
카프카는 모든 디렉토리에 대해 파일 핸들러를 열게 되는데, 이 때 파티션의 수가 늘게 되면 그 수 만큼 파일 핸들러 역시 많이지게 되어 리소스를 낭비하게 된다.

또 카프카는 고가용성을 위해 리플리케이션을 지원한다. 브로커에 존재하는 파티션들에 대해 각각 리플리케이션이 동작하게 되며 이중 하나는 파티션의 리더, 나머지는 팔로워로 동작하게 된다. 이 때, 만약, 리더의 브로커가 다운되게 되면 파티션의 팔로워중 하나가 리더로서 승격되어 동작하게 되는데, 새로운 리더를 선출 하는데 걸리는 시간은 곧 장애 시간으로 환산된다.
최악의 경우, 다운된 브로커가 컨트롤러일 경우, 컨트롤러가 살아있는 다른 브로커에게 완전히 넘어가기 전까지 새로운 리더를 선출 할 수 조차 없다.
파티션의 수가 많다면, 이 페일 오버 (Failover) 동작을 완수하는데 걸리는 시간이 더 길 것이며 장애 시간도 그 만큼 길게 된다.

따라서 이상적인 파티션의 갯수는 프로듀서/컨슈머 중 가장 많은 수와 동일 한 것이 적절하다고 할수 있다.

Offset, Message order

카프카에서는 각 파티션 마다 메세지가 저장되는 위치를 오프셋 (Offset) 이라고 부른다.
오프셋은 파티션 내에서 유일하고, 순차적으로 증가하는 64비트 정수로 되어있다.

프로듀서가 파티션 0에 메세지를 0, 1, 2, 3, 4, 5 로 저장했다면, 컨슈머는 무조건 동일하게 0, 1, 2, 3, 4, 5로 가져갈 수 밖에 없다. 즉, 절대로 메세지 순서가 바뀐 상태로는 가져갈 수 없다.

카프카의 고가용성과 리플리케이션

카프카는 앞서 언급 했듯이 리플리케이션을 지원한다.
물리적 장애가 발생하는 경우에도 고가용성을 보장할 수 있는 이유가 이 때문이다.
토픽 자체를 복제하지 않고, 토픽의 파티션들을 복제한다.

Replication Factor, Leader, Follower

  1. Replication Factor
    카프카 설정 파일에 다음과 같은 항목이 있다.
    default.replication.factor
    이 설정은 리플리케이션의 수를 설정하는 것이며 해당 항목이 없다면 기본 값인 default.replication.factor=1이 설정되어있다.
    아 설정은 아무 옵션 없이 카프카를 실행할 때 적용되는 값으로 변경하려면 설정 파일을의 해당 내용을 변경하거나 옵션을 주어 재시작해야한다.
    또한, 클러스터 내의 모든 브로커에 동일한 값을 설정해주어야 한다.
  2. Replication Leader, Follower
    리플리케이션된 파티션을 부르는 용어는 각 애플리케이션 마다 다르다. 카프카의 주키퍼에선 리더(Leader)와 팔로워(Follower)라고 부른다.
    모든 읽기, 쓰기 작업은 리더에서 수행된다. 팔로워들은 리더의 데이터를 그대로 리플리케이션만 하고 읽기, 쓰기 작업에는 관여하지 않는다. 따라서 리더와 팔로워는 순서와 오프셋이 동일한 메세지를 갖게된다. 물리적인 공간을 차지하는 크기도 동일하기 때문에 무조건 리플리케이션 팩터를 동일한 값으로 설정하기 보다는, 데이터의 중요도에 따라 다르게 두어 효율적으로 운영하는 것이 좋다.

Management of Replication Reader and Follower

카프카에서 리더와 팔로워는 각자 맡은 역할이 다르다.
리더는 모든 데티어의 읽기 쓰기에 대한 요청에 응답하면서 데이터를 저장해 나가고, 팔로워는 리더를 주기적으로 보면서 자신에게 없는 데이터를 리더로부터 주기적으로 가져오는 방법으로 리플리케이션을 유지한다. 카프카에서는 이 과정에서 정합성을 유지하기 위해 ISR(In Sync Replica)라는 개념을 도입했다.

In Sync Replica (ISR)

ISR 이란 현재 리플리케이션 되고있는 애플리케이션 그룹이다.
여기에는 중요한 규칙이 하나 있는데 이 규칙은 ISR에 속해 있는 구성원만이 리더의 자격을 가질 수 있다는 것이다.

ISR 의 동작 과정을 나열하면 다음과 같다.

  • 가정
    프로듀서 1개, 3개의 브로커, 1개의 리더, 2개의 팔로워
  • 동작 과정
    1. 기본 상태는 ISR이 모든 브로커의 파티션으로 그룹화.
    2. 프로듀서가 메세지 A를 토픽에 전송
    3. 토픽의 리더 파티션이 메세지를 저장, 요청에 응답.
    4. 팔로워 파티션이 리더의 변경을 감지, 동기화.
    5. ISR이 리더와 동기화 된 파티션을 대상으로 축소됨.

자세히 알아보자.

  1. 프로듀서는 A 라는 메세지를 토픽의 리더에게 전달한다.
  2. 프로듀서가 보낸 메세지 A는 토픽의 리더만이 처리하고, 요청에대한 응답을 전달한다.
    모든 메세지는 리더만이 읽기 쓰기작업을 수행할 수 있기 때문에 리더 파티션만 데이터를 다룬다. 이후 팔로워 파티션들은 이 리더의 변경을 짧은 주기로 확인하며 동기화를 시도한다.
    여기서 팔로워 2대중 1대 (편의상 1, 2번이라 하고, 2번에 장애가 발생했다 하자.)가 정상 동작하지 않는다. 리더는 설정된 주기만큼 팔로워들로 부터 확인 요청이 오지 않는다면, 해당 파티션을 정상작동하지 않는다고 판단, ISR에서 제외한다.
  3. 리더 파티션이 팔로워 파티션 2를 ISR 그룹에서 추방해 ISR 그룹이 축소된다. 팔로워 1은 계속해서 리더 파티션에게 변경 확인요청을 보내며 정합성을 유지한다.

이렇게 리더가 ISR을 관리해 가면서 다음 리더 후보군을 제한할 수 있다. 위 상황에서 만약 리더가 다운된다면, 팔로워1이 다시 리더로 승격하게 되고, 프로듀서와 컨슈머의 요청을 이어서 처리하게 된다.

모든 Broker 가 다운된다면?

위와 같은 상황에서 더 최악의 상황으로 가보자.
위의 3대의 브로커가 모두 다운이 된다면 어떻게 될지 상상해 보자. 이 경우 장애 복구 작업은 2가지 전략이 있을수 있다.

  1. 마지막 리더가 살아나기를 기다린다.
  2. ISR에서 추방되었지만, 먼저 살아나면 자동으로 리더가 된다.

데이터의 정확도에서는 1번이 가장 좋은 시나리오이지만 필수 조건이 요구된다.

재시작시, 마지막 리더가 반드시 시작되어야 한다.

경우에 따라서는 마지막 리더가 재시작 후에도 정상작동하지 못할 수 도 있다. 마지막 리더의 정상화 까지 장애는 유지될 것이다.

2번의 경우에는 메세지의 손실이 발생한다. ISR에서 추방된 브로커는, 마지막 리더에 있지만, 자신에게는 없는 메세지가 있을 수 있다. 그러나 1과는 다르게 빠른 서비스 정상화가 가능하다.

2가지 경우중 어느 것이 맞다고 할 수 없다. 카프카에서는 0.11.0 이하 버전에서 기본값으로 2번을 채택해 빠른 서비스 정상화 전략을 사용했으나, 이후의 버전부터는 1번을 채택해 정합성을 유지하는 전략을 사용하고있다.
그러나 사용자의 선택에 따라 관련 설정은 카프카의 설정 파일에서 원하는 옵션으로 변경할 수 있다.
unclean.leader.election.enable항목의 값을 true, false로 지정함에 따라 각각 2번, 1번의 전략을 사용한다.

카프카에서 사용하는 Zookeeper 와 Z-Node 의 역할

편의상 카프카의 지노드를 /root라 명명한다.

  1. /root/controller
    현재 카프카 클러스터의 컨트롤러 정보를 확인할 수 있다.
    리더를 선정하는 프로세스는 매우 종요하며 브로커의 실패 등으로 인해 리더가 변경되면 모든 파티션에 대해 파티션 마다 리더 선출 작업이 필요로하게 된다.
    컨트롤러는 브로커 레벨에서 실패를 감지하고 실패한 브로커에 의해 영향을 받는 모든 파티션의 리더 변경을 책임지고 있다.
    컨트롤러는 클러스터 내 브로커 중에 임의로 선정되고, 컨트롤러 브로커가 다운될 경우, 남은 브로커중 하나가 새로운 컨트롤러가 된다.

  2. /root/brokers
    브로커 관련된 정보들이 저장된다.
    설치 시 브로커 설정에서 수정한 broker.id를 확인 할 수 있다.
    브로커는 시작시 /root/brokers/idsbroker.id로 지노드를 생성해 자신을 등록한다.
    중복된 id 등록시 오류가 발생한다.

    주키퍼의 임시노드를 사용해 등록하고, 만약 브로커가 종료되거나 다운되면 지노드는 사라진다.
    /root/brokers/topics를 확인해보면 클러스터 내 토픽 정보들도 확인 할 수 있다.

    • 토픽의 파티션 수
    • ISR 구성 정보
    • 리더 정보
    • ETC.
  3. /root/consumers
    컨슈머 관련된 정보들이 저장되며, 컨슈머가 각각의 파티션들에 대한 오프셋 정보가 이곳에 저장된다. 지워지면 안되는 정보기 때문에 주키퍼의 영구 노드로 저장된다. 오프셋을 주키퍼에 저장할 수 있는 기능을 제공하고 있지만, 이후 릴리즈에서는 해당 기능이 Deprecate 될 것이다. 따라서 카프카의 topic에 오프셋을 저장하여 사용하는 것을 권장한다.

  4. /root/config
    토픽의 상세 설정 정보를 확인할 수 있다. 토픽 생성시 기본값으로 생성한 작업 외에 상세 설정 추가를 통해 retenstion.md등을 별도로 설정한 경우 해당 옵션 정보를 확인할 수 있다.