[Kafka] 카프카 클러스터에 적당한 토픽/ 파티션 개수는?
카프카 관리자 업무를 진행하면서 가장 많이 받는 질문 중 하나는 "파티션 개수는 몇 개가 적당합니까?"이다.
그래서 이번 글은 Confluent 공동 창업자 중 한명인 Jun Rao가 쓴 How to choose the number of topics/partitions in a Kafka cluster? 라는 블로그 글을 인용해서 파티션 숫자와 관련하여 정리한다.
필자의 글은 Jun Rao의 글을 바탕으로 이해한 부분들을 풀어서 썼기 때문에 해당 주제에 관심이 있는 분들은 Jun Rao의 원문을 다시 읽어보시길 추천한다.
많은 파티션은 높은 처리량을 이끈다.
카프카에 기본적인 지식을 가지고 계신 분이라면 카프카가 분산 처리의 목적으로 설계되었음을 안다. 카프카의 분산 처리를 가능하게 하는 핵심 개념이 토픽의 파티션이다. 프로듀서와 컨슈머는 여러 파티션에 동시에 접근해서 데이터를 처리하기 때문에 파티션이 많다면 처리량이 높아진다.
파티션 수를 결정하는 공식은 처리량에 기반으로 한다. 프로듀서(p), 컨슈머(c)의 한 파티션이 요구하는 처리량을 기준으로 파티션 수를 결정한다. 프로듀서의 처리량에 영향을 끼치는 요소로 배치 사이즈, 압축 코덱, Acks 타입, 복제 수 등이 있다. 2014년에 링크드인에서 수행한 벤치마크를 보면 한 파티션에 10MB/sec까지 속도가 나온다는 자료가 있다. 반면에 컨슈머는 컨슈머가 데이터를 처리하는 로직에 따라 처리량이 바뀐다.
기본적으로 파티션 수를 결정할 때, 1~2년 후의 처리량을 고려해서 결정한다. 또한 현재 카프카 클러스터의 처리량 대비 파티션 수를 결정하고 클러스터의 서버가 늘어나면 파티션을 늘리고 파티션을 적당히 분배시켜 줄 수 있다.
[메세지 Key 관련 추가 참고사항]
프로프로듀서에서 Key를 사용하면 파티션을 늘릴 때 고려해야 할 사항이 있다. key를 포함해서 카프카에 데이터를 보내면 key의 해시값을 기준으로 파티션이 결정된다. 만약 컨슈머가 처리하는 데이터가 Key를 기준으로 동일한 파티션에 위치해야 한다면 문제가 발생할 수 있다.
아래에서는 처리량 이외에 파티션 수를 결정할 때 고려해야 할 요소들을 다뤄보도록 하자. 계속 살펴보겠지만 너무 많은 파티션 수를 부정적인 영향을 끼칠 수 있다.
많은 파티션은 많은 파일 핸들러의 오픈이 필요하다 (More Partitions Requires More Open File Handles)
카프카 클러스터의 파티션은 개별적으로 디렉토리를 가진다. log segment 당 2개의 파일(index, actual data)을 생성한다. 각 브로커는 모든 log segment의 index, data 파일 핸들을 엽니다. 파티션이 너무 많다면 OS의 파일 핸들 제한 설정을 바꿔야 할 수 있다.
많은 파티션은 비가용성이 높아진다 (More Partitions May Increase Unavailability)
카프카는 내부적으로 파티션을 복제한다. 프로듀서와 컨슈머는 파티션의 리더 브로커와 통신을 하고 팔로워 브로커가 리더 브로커로부터 데이터를 가져와서 복제한다. 만약 브로커가 다운되면 해당 브로커가 담당하는 리더 파티션을 사용하지 못하게 된다. 카프카는 자동적으로 다른 팔로워에게 리더 역할을 맞긴다. 다른 리더를 선출하는 역할은 컨트롤러라 부르는 브로커 중 한 대의 서버에서 한다. 파티션의 메타 데이터는 주키퍼에 존재한다.
브로커를 정상적으로 종료할 때는 컨트롤러가 파티션 리더를 순차적으로 이동한다. 리더 이동은 몇 밀리초 밖에 소요되지 않는다. 그렇지만 브로커가 비정상 종료되었을 때는 상황이 다르다. 비가용성은 파티션 수에 비례해서 늘어난다. 200개의 파티션에 2개의 복제를 가진다고 하자. 대략적으로 1000개의 파티션 리더가 존재한다. 한 파티션의 새로운 리더를 결정하는데 5ms가 걸린다면 1000개의 파티션 리더를 결정할 때 5초가 소요된다. 클라이언트에서는 문제가 발생할 수 있는 시간이 될 수 있다.
만약 비정상 종료된 브로커가 컨트롤러 역할을 한다면 문제가 더 심해진다. 새로운 컨트롤러를 먼저 선출해야 하며, 새로운 컨트롤러는 주키퍼로부터 파티션 메타 데이터를 새로 받아와야 한다. 10000개의 파티션이 존재하고 한 파티션 메타 데이터를 가져오는데 2ms가 걸린다면 20초의 비가용 시간이 발생한다.
브로커의 비정상 종료는 일반적인 상황은 아니다. 그래도 파티션 수와 연관된 문제이니 한 브로커당 최대 파티션 숫자를 고려해서 관리해야 한다. 한 브로커 당 2000~4000개의 파티션, 전체 클러스터에 10000개로 제한하는 것을 추천한다. (다만 클러스터 숫자를 보여주지 않았고 현재는 컨트롤러의 재기동 시간이 2015년 시점에 비해 개선되었다. 관련 내용은 필자의 [Kafka] 컨트롤러 분석 글을 참고하자)
많은 파티션은 처리(대기)시간이 늘어난다 (More Partitions May Increase End-to-end Latency)
end-to-end latency (이하 처리시간)은 프로듀서가 보낸 데이터가 컨슈머에 이르기까지의 시간으로 하자. 컨슈머는 카프카에 커밋된 데이터만을 가져올 수 있다. 커밋되었다는 것은 모든 브로커에 복제가 완료되었음을 나타낸다. 브로커는 한 스레드에 의해서 복제를 처리한다 (기본 설정). 실험 상 1000개의 파티션을 다른 브로커에 복제할 때 20ms의 시간이 걸렸다. 이것은 컨슈머가 데이터를 가져가는데 20ms의 대기시간이 있음을 의미한다.
브로커가 많은 큰 클러스터에서 이 문제는 완화가 된다. 파티션 리더가 1000개이고 10개의 다른 브로커가 있다고 가정하자. 나머지 10개의 브로커는 각각 100개의 파티션만 가져오면 된다. 따라서 커밋으로 인한 대기 시간은 수십 ms가 아니라 몇 ms에 불과하다.
그래서 클러스터에 여러 개의 브로커가 존재하면 복제 시간은 줄어든다. 다음 수식으로 각 브로커당 파티션 수 최대치를 제안한다.
100 * b (브로커 수) * r (복제 수)
많은 파티션은 많은 클라이언트 메모리를 필요로한다 (More Partitions May Require More Memory In the Client)
0.8.2 버전에서 프로듀서의 주요한 기능 중 하나로서 사용자가 메시지를 버퍼링하는데 사용되는 메모리 상한을 설정할 수 있다는 것이다. 프로듀서는 파티션 당 메세지를 버퍼를 가진다. 충분한 시간이 지나면 버퍼에 누적된 메세지가 브로커에 전송된다. 파티션이 늘어나게 되면 Producer가 사용하는 메모리양이 제한을 초가할 수 있다.
Consumer도 비슷한 문제가 있다. Consumer는 파티션당 메세지를 일괄로 가져온다. 더 많은 파티션을 소비하려면 많은 메모리가 필요하다.
파티션 수 결정과 관련하여 정리를 했다. 카프카를 통해 서비스를 개발하는 입장에서는 처리량을 높이기 위해 파티션을 무조건 높여야 한다고 생각할 수 있다. 그러나 카프카 관리자 측면에서는 다른 측면도 고려해야 한다. 명확한 정답은 없다. 하지만 처리량과 카프카 운영을 위해 파티션 수를 상황에 맞춰 관리하는 것 만이 정답으로 보인다.
관련 문서