mac OS 카프카 설치 & 실행
brew install kafka
brew services start kafka
brew services start zookeeper
카프카와 주키퍼 서버를 띄운다.
zookeeper?
카프카 클러스터의 메타데이터와 컨슈머 클라이언트에 대한 정보를 저장
이 외에 다양한 설정을 할 수 있도록 하는 중앙화된 서비스
카프카 운영을 위해 같이 사용되며, 최신 카프카 버전에서는 zookeeper 에 의존하는 점을 개선하려 zookeeper 없이 실행할 수 있도록 변화함
telnet 을 사용하여 주키퍼 서버 테스트하기
telnet localhost 2181
Trying ::1...
Connected to localhost.
Escape character is '^]'.
srvr
Zookeeper version: 3.9.2-${mvngit.commit.id}, built on 2024-03-11 21:09 UTC
Latency min/avg/max: 0/2.4848/17
Received: 67
Sent: 68
Connections: 2
Outstanding: 0
Zxid: 0x1d
Mode: standalone
Node count: 28
Connection closed by foreign host.
srvr 을 입력하면 다음과 같이 주키퍼 서버의 정보를 출력한다.
주키퍼 앙상블
주키퍼는 고가용성을 보장하기 위해 앙상블이라는 클러스터 단위로 동작한다.
주키퍼의 부하 분산 알고리즘때문에 홀수 개의 서버를 운영하는 것이 권장되며, 5대의 서버를 추천하고 있다.
앙상블 멤버(쿼럼이라고 부름, 주키퍼 서버)의 과반 이상이 작동하고 있어야 주키퍼가 동작하기 때문이다.
카프카 동작 확인하기
cd /opt/homebrew/opt/kafka/libexc/bin # 카프카 실행 sh 파일 위치 폴더
./kafka-topics.sh -create --topic test --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1
./kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic test
Topic: test TopicId: f2jG-YKDSKOK1Q14TtsfEw PartitionCount: 1 ReplicationFactor: 1 Configs:
Topic: test Partition: 0 Leader: 0 Replicas: 0 Isr: 0 Elr: N/A LastKnownElr: N/A
-create --topic 를 통해 토픽을 생성한다. replica, partition 은 각 1개씩 설정하였다.
--describe --topic 를 통해 생성한 토픽의 정보를 출력한다.
localhost 의 9092 포트는 default 설정으로 띄운 카프카 브로커의 포트이다.
카프카 토픽에 메시지 쓰기
./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test
>Test msg1
>Test msg2
>^C%
토픽에서 메시지 읽기
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
Test msg1
Test msg2
^CProcessed a total of 2 messages
위에서 살펴본 예제로도 독립 실행되는 서버를 실행시킬수는 있다. 그러나 대규모 프로젝트에서 운영을 하기 위해서는 구성을 제어하고 설정을 튜닝할 수 있어야 한다. 설정의 대부분은 특정 활용사례가 있는 것이 아닌 한, 바꿀 일이 없는 튜닝 관련 옵션이긴 하다.
핵심 브로커 매개변수
broker.id
카프카 브로커마다 할당되는 정수값 식별자
호스트별로 별도의 id 를 구성하는 것이 강력히 권장된다. 유지보수 시 브로커 ID에 해당하는 호스트가 무엇인지 찾기도 어렵기 때문.
listeners
쉼표로 구분된 리스너의 이름과 URI의 목록
listeners 에 정의한대로 연결을 받게 된다.
예제 설정 파일에서는 9092번 TCP 포트에서 실행하도록 정의해두었기 때문에 localhost 9092 포트에서 카프카 브로커를 바로 실행할 수 있었다.
zookeeper.connect
브로커의 메타데이터가 저장되는 주키퍼의 위치
예제 설정 파일에서는 localhost:2181로 설정되어 있다.
log.dirs
카프카는 모든 메시지를 로그 세그먼트 단위로 묶어서 log.dir 설정에 지정된 디스크 디렉토리에 저장한다.
여러 디렉토리를 지정할 경우 log.dirs 설정을 사용하며, 쉼표로 구분하여 디렉토리들을 지정한다.
새로운 파티션이 자신의 로그를 저장할 디렉토리를 배정받을 때는, 실제 로그 디렉토리들의 용량은 관계없이 배정된 파티션의 수가 균등하도록 배정된다.
num.recovery.threads.per.data.dir
로그 디렉토리별 할당될 스레드의 개수
로그 세그먼트 파일을 열고 닫는 역할을 하며, 장애 발생 후 다시 시작했을 경우에는 각 파티션의 로그 세그먼트를 검사하여 잘못된 부분을 삭제하는 역할도 한다.
스레드를 작게 잡을 경우 병렬처리가 제한되어 장애 발생 이후 다시 시작할 때 이 설정 때문에 몇 시간씩 차이가 발생할 수도 있다.
auto.create.topics.enable
기본적으로 true 로 설정되어 프로듀서가 메시지를 쓰거나, 컨슈머가 메시지를 읽거나, 클라이언트가 메타데이터를 요청하거나 하는 상황에서 브로커가 토픽을 자동으로 생성하여 동작하도록 한다.
명시적으로 토픽을 관리하고 싶다면 false 로 놓을 수 있다.
auto.leader.rebalance.enable
모든 토픽의 리더 역할이 하나의 브로커에 집중되어 카프카 클러스터의 균형이 깨지는 것을 막기 위해 자동으로 리더 역할을 분산시키도록 하는 설정
delete.topic.enable
토픽을 임의로 삭제하지 못하도록 막아야 할 때 사용하는 설정
새롭게 토픽을 생성할 때 수많은 설정의 기본값도 지정할 수 있다. 몇몇 설정은 관리용 툴을 사용해서 토픽 단위로 설정할 수 있다.
num.partitions
몇 개의 파티션을 갖게 할 지 설정
많은 사용자들이 파티션의 개수를 클러스터 내 브로커의 수와 맟추거나 배수가 되도록 하여 균등하게 분산처리를 할 수 있도록 설정한다.
default.replication.factor
몇 개의 복제 팩터를 갖게 할 지 설정
min.insync.replicas 설정값보다 최소 1 이상 크게 잡을 것을 강력히 권장함
안정적인 운영을 위해서는 2 이상 잡는 것을 권장하며 이를 RF++ 이라고도 함. 변경을 위해 하나가 중지된 상태에서 장애가 발생하여 하나가 더 중지되어도 최소 한 개는 남아있기 때문
log.retention.ms
메시지를 얼마나 오래 보존할 것인지
기본값은 log.retention.hours 를 사용하며 168시간, 1주일이다.
hours, minutes 등 다양한 설정값이 있지만 작은 단위가 우선권을 갖기 때문에 ms 로 설정하는 것이 권장된다.
log.retention.bytes
메시지를 얼마만큼의 용량만큼 보존할 것인지
파티션 단위로 적용된다.
-1 로 잡으면 영구히 메시지가 보존된다.
log.segment.bytes
로그 세그먼트의 사이즈
브로커에 쓰여진 메시지는 해당 파티션의 현재 로그 세그먼트의 끝에 추가되며, 사이즈(기본 1GB)를 초과하면 로그 세그먼트 파일을 닫고 새로운 파일을 연다.
너무 작게 설정하면 자주 파일을 열고 닫아 디스크 쓰기의 효율이 떨어지게 되며, 너무 크게 잡게 되면 오래 전에 쓴 메시지와 최신 메시지가 같은 로그 세그먼트 파일에 담겨, 로그 세그먼트를 삭제하거나 탐색하는 등의 작업은 파일 단위로 수행되기 때문에 사용에 어려움이 생긴다.
작게 설정하고 필요 시 크게 변경하자.
참고. 위의 보존 시간, 용량 설정은 로그 세그먼트 기준이다.
log.roll.ms
로그 세그먼트를 닫을 시간을 설정
log.segment.bytes설정은 용량, log.roll.ms설정은 시간 단위로 로그 세그먼트 파일을 닫는다.
기본값은 설정하지 않음이며, 여러 세그먼트 파일이 용량이 덜 차서 한 번에 닫히게 되면 일시적으로 성능이 안나올 수 있다.
min.isync.replicas
최신 상태로 프로듀서와 동기화 될 레플리카의 수(기본값 1, 리더 하나)
리더가 쓰기 작업에 응답하고 직후에 장애가 발생하여 최근의 쓰기 작업 내역을 복제하기 전에 다른 레플리카로 리더 역할이 옮겨지게 되면 데이터 유실이 발생하는데, 이 설정값을 2 이상으로 잡아주면 유실을 방지할 수 있다.
데이터 몇 개의 유실은 상관 없는 경우 성능 오버헤드를 고려해 기본값 1로 그대로 두는 것이 나을 수 있다.
message.max.bytes
쓸 수 있는 메시지의 최대 크기 제한 (기본값 1,000,000 = 1MB)
크기는 압축 이후 크기를 기준으로 한다.
메시지 크기가 커질수록 브로커 스레드의 요청당 작업 시간도 증가하여 성능에 영향을 미칠 수 있다.
읽을 수 있는 메시지의 크기 제한과 맞추어야 에러가 발생하지 않는다. (fetch.message.max.bytes, replica.fetch.max.bytes)
카프카 자체가 어떠한 하드웨어 구성을 요구하지는 않으나, 성능을 고려하여 하드웨어를 선택해야한다.
디스크 처리량
읽기 쓰기 요청이 많은 경우 SSD, 자주 쓸 일이 없는 데이터를 많이 저장해야할 경우 HDD
디스크 용량
위의 설정값들을 고려해 필요한 디스크 용량을 측정해야한다. 예를 들어, 브로커가 하루에 1TB의 트래픽을 받을 것으로 예상되고, 메시지를 1주일간 보존한다면, 최소 7TB의 디스크 용량이 필요하며, 다른 파일도 감안해서 10% 정도 오버헤드를 고려해야한다.
확장 시 브로커를 늘려 전체 디스크 용량도 늘릴 수 있다.
메모리
컨슈머는 대개 프로듀서가 막 생성한 메시지를 뒤따라오며 읽는다. 따라서, 생성한 메시지가 페이지 캐시에 남아있을 때 바로 컨슈머가 읽어 디스크 I/O 보다 빠르게 처리 될 수 있도록 하면 성능을 높일 수 있다.
카프카 그 자체는 JVM 에 많은 힙 메모리를 필요로 하지 않아 설정된 메모리의 남는 부분을 페이지 캐시로 사용한다.
캐싱을 통해 성능을 향상 시켜야 하므로 하나의 시스템에서 다른 애플리케이션과 함께 운영하는 것을 권장하지 않는다. (캐시 히트 rate 가 낮아질 것이므로)
네트워크
프로듀서 하나에 여러 컨슈머가 붙는 경우가 많아, 유입되는 네트워크 사용량과 유출되는 네트워크 사용량이 불균형을 이루어 측정이 복잡해진다.
네트워크 처리량을 낮게 잡아 복제나 미러링 작업이 후순위로 밀려 취약한 시스템이 되는 경우도 많이 발생한다.
CPU
기본적으로 CPU 성능은 다른 요소에 비해 중요하지 않다.
압축되어 받은 메시지를 체크섬을 확인하고, 압축을 해제하여 오프셋을 부여하는 정도의 연산이면 충분하기 때문.
클러스터가 엄청 거대해져 위의 연산도 많은 처리가 필요해진다면 CPU의 성능을 올리는 것도 고려해볼만 하다.
다수의 브로커로 하나의 클러스터를 구성하여 안정적으로 운영하기 위해 필요한 설정들을 알아보자.
브로커 설정
클러스터 내의 모든 브로커는 동일한 zookeeper.connect 값을 가져야한다. 클러스터 메타데이터를 저장하는 주키퍼 앙상블을 같은 것으로 사용해야 하기 때문.
broker.id 는 클러스터 내 모든 브로커가 유일한 값들을 가져야한다. 같은 값을 가진 브로커가 있다면 나중에 생성되는 브로커에서 에러가 발생한다.
운영체제 튜닝하기
리눅스 배포판에는 웬만한 애플리케이션에 잘 동작하는 커널 매개변수가 잘 잡혀있지만, 몇 가지 설정을 변경하여 카프카 브로커의 성능을 끌어올릴 수 있다.
가상메모리
카프카는 페이지 캐시를 많이 사용하기 때문에 스와핑이 자주 일어나는 것은 성능을 크게 낮출 수 있다. 따라서 vm.swappiness 설정값을 1로 설정하여 스왑 공간보다 우선적으로 페이지 캐시를 더 사용하도록 설정할 수 있다.
더티 페이지를 관리하는 방식을 변경하여 성능을 올릴 수도 있는데, 메모리에 더티 페이지가 일정량 이상 차지하면 강제로 하드 디스크와 동기화를 시작하는데, 이 작업이 발생하지 않도록 더티 페이지 최대 비율(vm.dirty_ratio) 를 기본값 20에서 60~80으로 늘리고, vm.dirty_background_ratio 를 기본값 10에서 5로 낮춰 더 자주 적은 양의 더티 페이지를 백그라운드 프로세스에서 디스크에 쓸 수 있도록 할 수 있다.
위와 같이 더티 페이지를 관리하는 방식을 변경하게 되면 데이터 유실이 발생할 위험이 높아지므로 복제 기능을 활성화해 안전장치를 해놓을 것을 권장한다.
디스크
디스크 성능에 큰 영향을 미치는 부분은 하드웨어 설정 다음으로 디스크의 파일 시스템이다. 대부분 Ext4, XFS 라는 파일시스템을 사용하는데, XFS 파일 시스템이 flush가 덜 일어나도록 하거나, 기본 설정으로 수행되는 튜닝만으로도 Ext4 보다 더 나은 I/O 처리량을 보여준다
파일시스템을 뭐로 설정했든 간에 마운트 옵션으로 noatime 옵션을 주는 것이 좋다. 파일 메타데이터에는 생성 시각(ctime), 마지막 수정 시각(mtime), 마지막 사용 시각(atime) 이 있는데, atime 은 카프카에서 전혀 사용되지 않으므로 noatime 옵션으로 불필요한 디스크 I/O 를 줄일 수 있다.
크기가 큰 디스크 쓰기 작업을 수행하는 경우 largeio 옵션으로 효율을 높일 수 있다.
네트워킹
다른 웹 애플리케이션, 웹 서버와 동일하게 권장되는 설정이다.
큰 전송을 주고 받을 때 성능을 향샹시키기 위해 소켓별 송/수신 버퍼의 기본크기를 늘릴 수 있다. net.core.wmem_default/net.core.rmem_default 매개변수인데, 합리적인 설정값은 131072(128KB) 이다. 최대 크기도 늘리는 것이 좋은데, net.core.wmem_max/net.core.rmem_max 매개 변수로 2097152(2MB) 가 적당하다.
이 외에도 TCP 소켓 버퍼 사이즈, TCP 윈도우 스케일링 기능, 커넥션 수를 늘리는 등 다양한 설정을 통해 성능을 향상시킬 수 있다.
가비지 수집기 옵션
기본적으로 카프카에서는 Java의 G1GC 를 권장한다. 카프카는 G1GC가 출시되어 안정화 되기 전에 발표되어 CMS라는 가비지 컬렉터를 사용하는데, KAFKA_JVM_PERFORMANCE_OPTS 환경변수를 설정하여 쉽게 변경할 수 있다.
MaxGCPauseMillis 설정을 통해 가비지 컬렉터 수행 동안 선호되는 중단 시간을 설정할 수 있다. 이 값을 설정해도 G1GC에서 필요한 경우 시간을 넘기기도 한다.
InitiatingHeapOccupancyPercent 옵션의 기본값은 45인데, 전체 힙의 45%가 사용되기 전까지는 가비지 컬렉터가 동작하지 않게 됨을 의미한다. 이 값을 상황에 맞게 수정하여 성능을 향상 시킬 수 있다.
데이터센터 레이아웃
모든 브로커들이 같은 데이터센터에 같은 랙에 속하도록 하는 것은 가용성이 좋지 않다. 단일 장애점이 없도록 같은 데이터센터라도 broker.rack 설정을 통해 각각 랙을 설정할 수 있다.