윈도우, mac, 리눅스 등 다양한 운영체제를 지원하지만, 리눅스가 권장됩니다.
주키퍼나 카프카는 모두 JDK위에서 작동하기에 자바설치가 필수입니다.
아파치 카프카는 카프카 클러스터의 메타데이터와 컨슈머 클라이언트에 대한 정보를 저장하기 위해 아파치 주키퍼를 사용합니다.
주키퍼는 설정 정보 관리, 이름 부여, 분산 동기화, 그룹 서비스를 제공하는 중앙화된 서비스입니다.
해당 블로그 글에서는 설치보단 사용되는 설정에 대해 집중적으로 다룹니다.
아파치 주키퍼는 여러 대의 컴퓨터나 서버 간에 데이터를 동기화하고 관리하는 데 사용됩니다. 이것은 대규모 분산 시스템에서의 일관성, 가용성, 분할 허용 등의 문제를 해결하기 위해 설계되었습니다.
분산 코디네이션: 주키퍼는 여러 서버 간의 상태와 구성 정보를 동기화하고 유지하는 데 사용됩니다. 이를 통해 서버 간의 협력이나 리더 선출과 같은 작업을 효과적으로 수행할 수 있습니다.
분산 락 관리: 주키퍼는 분산 환경에서의 락 관리에 사용됩니다. 여러 프로세스 간에 동기화된 작업을 수행하려면 락이 필요한데, 주키퍼는 이를 지원하여 안전하게 락을 획득하고 해제할 수 있게 합니다.
분산 구성 관리: 주키퍼는 시스템의 구성 정보를 저장하고 관리하는 데 사용됩니다. 시스템의 설정이나 구성이 변경될 때 이를 감지하고 업데이트할 수 있습니다.
분산 메시징: 주키퍼는 작은 양의 데이터를 안전하게 분산시키는 메시징 시스템으로도 사용됩니다.
주키퍼는 다양한 분산 시스템에서 중요한 역할을 수행하며, Hadoop, HBase, Apache Kafka 등 여러 프로젝트에서 사용되고 있습니다.
주키퍼는 대부분의 설정 파일(/usr/local/zookeeper/config/zoo_sample.cfg)과 함께 배포됩니다.
주키퍼는 고가용성을 보장하기 위해 앙상블
이라 불리는 클러스터 단위로 작동하도록 설계되었습니다. 부하 분산 알고리즘에 따라 홀수대의 클러스터(3개, 5개)를 가지는 것이 권장됩니다.
이는 마스터 슬레이드 구조에서 투표를 통해 마스터를 재 위임하는 과정과 동일합니다.
주키퍼 설정에는 다음과 같은 설정을 지정할 수 있습니다.
tickTime=2000
dataDir=/var/lib/zookeeper
clientport=2181
initLimit=20
syncLimit=5
server.1=zoo1.example.com:2888:3888
server.2=zoo1.example.com:2888:3888
server.3=zoo1.example.com:2888:3888
initLimit
: 팔로워가 리더와 연결할 수 있는 최대 시간(초기화 제한 시간)syncLimit
: 팔로워가 리더와 연결할 수 있는 최대 시간(동기화 제한시간)tickTime
: 시간 단위 (20 * 2,000밀리초)모든 서버의 호스트명을 다음과 같이 정의해야 합니다.
server.{X} = {hostname}:{peerPort}:{leaderPort}
X
: 서버의 아이디hostname
: 서버의 호스트 명 또는 IP
주소peerPort
: 앙상블 안의 서버들이 서로 통신할 때 사용하는 TCP
포트 번호leaderPort
: 리더를 선출하는 데 사용되는 TCP
포트 번호모든 카프카 브로커는 정숫값 식별자를 가집니다. 이 값은 클러스터 안의 각 브로커별로 전부 달라야 합니다.
카프카의 리스너는 다음과 같은 형태로 정의됩니다.
{프로토콜}://{호스트 이름}:{포트}
실 예는 다음과 같습니다.
PLAINTEXT://localhost:0902,SSL//:0901
호스트 주소를 0.0.0.0으로 잡을 경우 모든 네트워크 인터페이스로 부터 연결을 받게 됩니다.
브로커의 메타데이터가 저장되는 주키퍼의 위치를 정의합니다.
예제에서는 다음과 같은 주소를 활용합니다.
localhost:2181
카프카는 모든 메시지를 로그 세그먼트단위로 묶어서 log.dir
설정에 지정된 디스크 디렉토리에 저장합니다.
해당 설정은 로그 세그먼트를 관리할 스레드 수를 의미합니다. 카프카는 스레드 풀을 사용해 로그 세그먼트를 관리합니다. 이는 다음 작업을 수행합니다.
이 설정값을 잡아줄 때는
log.dirs
에 지정된 로그 디렉토리별 스레드 수라는 점을 명심해야 합니다. 예를 들어num.recovery.threads.per.data.dir
가 8이고,log.dirs
에 지정된 경로 수가 3개일 경우, 전체 쓰레드는 24개가 됩니다.
카프카 기본 설정에는 아래와 같은 상황에서 브로커가 토픽을 자동생성하도록 되어 있습니다.
카프카에 토픽을 생성하지 않고 존재 여부만을 파악할 수 없기에 명시적으로 토픽을 관리하고자 한다면 해당 설정을 false
로 할 수 있습니다.
해당 설정을 활성화 하면 파티션의 분포 상태를 주기적으로 체크하는 백그라운드 쓰레드가 돌며 리밸런싱을 진행합니다.
제곧내
새로운 토픽이 생성될 때 몇 개의 파티션을 갖게 되는지를 결정합니다. 기본값은 1
입니다.
보통 클러스터 내 브로커의 수와 맞추거나 배수로 결정합니다. 예를 들어 10개의 파티션으로 이루어진 토픽이 10개의 호스트로 구성된 카프카 클러스터에서 작동 중이고, 각 파티션의 리더 역할이 이 10개의 호스트에 분산되어 있다면 최적의 처리량이 나올 것입니다.
파티션을 수를 지정할 때는 다음과 같은 요소를 고려해야 합니다.
자동 토픽 생성 기능이 활성화되어 있을 경우, 이 설정은 토픽의 복제 팩터를 결정합니다. 간단히 말하자면 토픽 당 레플리카 셋을 몇개를 가져갈 지를 의미합니다.
메시지를 보존 주기 설정을 의미합니다.
메시지 만료의 또 다른 기준으로써 메시지 용량을 지정합니다.
8개의 파티션을 가진 토픽에 log.retention.bytes
의 설정값이 1GB로 잡혀 있다면, 토픽의 최대 저장 용량은 8GB
가 되는 것입니다. 모든 보존 기능은 파티션 단위로 작동하는 것이지 토픽 단위로 작동하는 게 아닙니다.
메시지 보존 주기 및 크기의 설정이 겹치게 되면 OR 조건을 통해 삭제 됩니다.
카프카 브로커에 쓰여진 메시지는 해당 파티션의 현재 세그먼트의 끝에 추가됩니다. 로그 세그먼트의 크기가 log.segement.bytes
에 다다르면 브로커는 기존 로그 세그먼트를 닫고 새로운 세그먼트를 엽니다.
메시지 크기에 따른 적절한 로그 세그먼트 설정이 필요합니다.
로그 세그먼트 파일이 닫히는 시점을 제어하는 또 다른 방법입니다. 이는 시간을 지정하여 로그 세그먼트를 닫습니다.
데이터를 지속성 위주로 클러스터를 설정할 때 min.insync.replicas
를 2로 잡아주면 최소한 2개의 레플리카가 최신 상대로 프로듀서와 동기화되도록 할 수 있습니다.
이는 프로듀서의 ack
설정을 all
로 잡아주는 것과 함께 사용됩니다. -> 쓰기 작업이 성공하기 위해 최소한 두 개의 레플리카가 응답해야 합니다.
쓰기 작업이 많다면 기본값인 1
을 권장합니다.
메시지의 최대 크기를 제한합니다. 기본은 1MB
입니다.
디스크 처리량, 용량, 메모리, 네트워크 CPU를 감안하여 하드웨어를 설정합니다.
메시지가 커밋될 때 로컬 디스크에 커밋되어야 하며 디스크 처리량은 쓰기 지연과 직접적인 관련이 됩니다.
메시지의 보존 기간 또는 보존 용량에 따라 설정해야 합니다.
하루마다 1TB의 트래픽을 일주일간 보존해야 한다면, 브로커는 로그 세그먼트를 저장하기 위한 저장 공간이 최소한 7TB
필요할 것입니다. 다른 저장해야 할 파일도 감안하여 +10%의 오버헤드를 고려하는 것을 권장합니다.
카프카 컨슈머는 프로듀서가 막 추가한 메시지를 바로 뒤에서 쫓아가는 식으로 파티션의 맨 끝에서 메시지를 읽어오는 것이 보통입니다.
이러한 상황에서 최적의 작동은 시스템 페이지 캐시에 저장되어 있는 메시지들을 컨슈머가 읽어 오는 것이 됩니다. 따라서, 시스템에 페이지 캐시로 사용할 수 있는 메모리를 더 할당해 줌으로써 컨슈머 클라이언트 성능을 향상시킬 수 있습니다.
카프카를 하나의 시스템에서 다른 어플리케이션과 함께 운영하는 것을 권장하지 않는 주된 이유가
메모리
입니다. 이는 페이지 캐시를 나눠쓰게 때문이고, 컨슈머의 성능을 제한시킵니다.
사용 가능한 네트워크 대역폭은 카프카가 처리할 수 있는 트래픽의 최대량을 결정합니다.
네트워크 인터페이스가 포화상태에 빠질 경우 클러스터 내부의 복제 작업이 밀려서 클러스터가 취약한 상태로 빠지는 경우가 종종 있습니다.
장비를 신청할 때 인프라에 따른
네트워크 처리량
도 꼭 고려해야 합니다. Bandwidth가 충분하지 않음에 따라 메모리 및 디스크에 영향이 갈 수 있습니다.
CPU는 디스크나 메모리만큼 중요하지는 않습니다.
하지만 메시지를 압축하거나, 체크섬을 확인하는 것, 오프셋을 부여하는 등 다양한 작업에 CPU를 사용합니다. 하지만 이런 작업은 카프카에 있어서 주된 작업은 아닙니다.
AWS, 마이크로소프트 애저, 네이버 클라우드 등 다양한 클라우드에서의 카프카를 제공하지만 이는 회바회임으로 패스
여러 대의 브로커를 하나의 클러스터로 구성할 수 있습니다.
카프카 클러스터의 적절한 크기를 결정하는 요소는 다음과 같습니다.
가장 먼저 고려할 요소는 디스크 용량과 단일 브로커가 사용할 수 있는 저장소 용량입니다.
예를 들어 클러스터가 10TB의 데이터를 저장해야 합니다. 하나의 클러스터가 저장할 수 있는 용량이 2TB라면 클러스터는 최소 5개가 됩니다. 복제 팩터를 증가 시킬 경우 이는 N
을 곱해야 합니다. 복제 팩터를 2로 잡으면 최대 10개의 브로커가 필요합니다.
다수의 카프카 브로커가 하나의 클러스터를 이루게 하기 위해서 설정해 줘야 하는 건 두 개 뿐입니다.
가상 메모리 및 네트워크 서브시스템, 로그 세그먼트를 저장하기 위해 사용되는 디스크 마운트 설정 등을 튜닝하여 성능을 최적화할 수 있습니다.
카프카의 경우 부하 특성에 맞게 스왑 공간이나 더티 메모리 페이지가 사용되는 방식으로 조정할 수 있습니다.
더티 메모리 페이지란??
커널은 page cache를 이용해서 디스크의 정보를 메모리에 잠시 저장하고,
필요할 때마다 메모리에 접근하여 속도를 향상시킬 수 있다.이때 디스크에 쓰기 작업이 필요한 경우,
디스크에 직접 쓰지 않고 만들어놓은 페이지 캐시에 쓰는데 이렇게 write가 일어난 페이지를 dirty page라 한다.
dirty page가 최종적으로 저장되기 위해서는 더티 페이지가 발생한 메모리 영역은 디스크에 동기화되어야 한다.
보통은 커널 스레드가 flush를 하여 더티 페이지를 디스크에 동기화하며,I/O가 많이 발생하는 서버는 더티 페이지가 언제 얼마나 동기화되느냐가 성능 튜닝의 중요한 요소가 된다.
스왑 공간을 아예 할당하지 않을 수도 있습니다. 스왑 공간은 메모리가 부족할 때 운영체제가 실행 프로세스를 강제 종료하는 것을 방지할 수 있습니다. 하지만 이는 카프카 어플리케이션에서 필수는 아니기 때문에 스왑 메모리보다 페이지 캐시 쪽에 더 많은 메모리를 할당해주는 것이 좋습니다.
리눅스의 파일 시스템의 대부분의 경우 Ext4
나 XFS
중 하나를 로컬 파일시스템으로 사용합니다. XFS
는 직접 튜닝의 필요 없이, 파일시스템에 의해 자동으로 수행되는 튜닝만으로도 카프카의 작업 부하에 대해 좋은 성능을 보여줍니다.
카프카는 대량의 데이터를 빠르게 주고받기에 리눅스의 네트워킹 스택의 기본 설정 값을 종종 수정합니다.
소켓의 송신, 수신 버퍼에 할당되는 기본/최대 메모리량
net.core.wmem_default
net.core.rmem_default
TCP 소켓의 송신, 수신 버퍼 크기
net.core.wmem_max
net.core.rmem_max
브로커가 동시에 받을 수 있는 클라이언트 수
net.ipv4.tcp_max_syn_backlog
등등
GC설정은 어플리케이션이 메모리를 어떻게 사용하는지에 대해 자세히 알아야할 뿐만 아니라 상당한 시행착오를 거쳐야 합니다.
카프카에서는 G1GC
를 기본 GC
를 사용하는 것이 권장됩니다. 이는 서로 다른 작업 부하를 자동으로 조절하고 어플리케이션이 실행되는 동안 일정한 정지 시간을 유지하도록 설계되었습니다.
G1GC
의 성능을 조절할 수 있습니다.
MaxGCPauseMillis
InitiatingHeapOccupancyPercent
G1GC
가 돌아가는 최대 메모리 사용량을 정의합니다. ex) 45면 전체 힙의 45%가 되기전까지는 GC가 돌지 않습니다.카프카 브로커는 힙 메모리를 상당히 효율적으로 사용할 뿐 아니라 GC의 대상이 되는 객체 또한 적게 생성하기에 이 설정값들은 낮게 잡아줘도 좋습니다.
카프카는 브로커에 새 파티션을 할당할 때 랙 위치를 고려하여 특정 파티션의 레플리카가 서로 다른 랙에 배치되도록 할 수 있습니다.
전반적으로, 카프카 클러스터의 각 브로커가 서로 다른 랙에 설치되도록 하거나 아니면 최소한 전원이나 네트워크와 같은 인프라 서비스 측면에서 단일 장애점이 없도록 하는 것이 모범적인 방법입니다.
카프카는 브로커, 토픽, 파티션에 대한 메타데이터 정보를 저장하기 위해 주키퍼를 사용합니다. 컨슈머 그룹 멤버나 카프카 클러스터 자체에 뭔가 변동이 있을 때만 주키퍼 쓰기가 이루어집니다.
현재 카프카에서 주키퍼를 활용하는지?
주키퍼 -> 브로커(프로듀서) -> 컨슈머로 이루어지는 카프카
카프카는 메시지를 모두 로그 세그먼트로 저장
카프카 어플리케이션 하드웨어
클러스터당 적절한 브로커 개수
카프카 운영체제 튜닝
데이터 센터에서의 카프카
카프카 주키퍼?
https://dobby.work/development/kafka-2/#!newthread
https://seungjuitmemo.tistory.com/340