02. 카프카 설치하기
카프카를 설치하고 간단한 설정 작업을 통해 실습하는 시간을 가져보자. 브로커의 메타 데이터를 저장하기 위해 사용되는 아파치 주키퍼에 대한 설치 또한 진행한다.
- 아파치 카프카 최신 버전에서는 주키퍼(ZooKeeper)에 대한 지원이 중단된다.
- KRaft(Kafka Raft Metadata Model)이라는 새로운 메커니즘으로 대체된다.
- 위에 대한 내용은 SK 테크 블로그 DEVOCEAN - Apache Kafka의 새로운 협의 프로토콜인 KRaft에 대해(1)를 참조하자.
- 주키퍼에 대한 지원이 중단된다고 하더라도 해당 메커니즘 파악을 위해 실습은 동일하게 진행한다.
# 주키퍼
- 설정 정보 관리, 이름 부여, 분산 동기화, 그룹 서비스를 제공하는 중앙화된 서비스
- 카프카 클러스터의 메타 데이터
- 컨슈머 클라이언트에 대한 정보
# 주키퍼 앙상블
- 주키퍼 앙상블(ZooKeeper Ensemble)
- 주키퍼는 고가용성을 보장하기 위해 앙상블이라는 클러스터 단위로 작동하도록 설계됨
- 주키퍼의 부하 분산 알고리즘 때문에 앙상블은 홀수 개의 서버 (e.g. 3, 5, 7 …) 를 가지는 것이 권장
- 주키퍼가 요청에 응답하려면 앙상블 멤버(쿼럼, quorum)의 과반 이상이 작동하고 있어야하기 때문
# 주키퍼 앙상블 크기 결정
- 5개의 노드 크기 고려
- 앙상블 설정을 변경할 수 있게 하려면, 1번에 1대의 노드를 정지 → 설정 변경 → 재시작 과정 필요
- 앙상블이 2대 이상의 노드 정지를 받아낼 수 없으면 정비 작업 위험
- 9대 이상의 노드 사용 권장 ❌
- 합의(consensus) 프로토콜 특성상 성능이 내려가기 시작하기 때문
- 클라이언트 연결이 너무 많아서 5대 / 7대 노드가 부하를 감당하기 힘든 상황
- 옵저버 노드를 추가하여 읽기 전용 트래픽 분산 시도
# 주키퍼 설정 파일
주키퍼 서버 앙상블 구성 시 필요한 요소
- 각 서버는 공통된 설정 파일 사용 (앙상블에 포함된 모든 서버의 목록 포함되어있음)
- 각 서버는 데이터 디렉토리에 자신의 ID 번호를 지정하는 myid 파일 가지고 있어야함
|
|
initLimit
: 파티션 팔로워 - 리더 연결할 수 있는 최대 시간 (초기화 제한 시간)- 이 시간 동안 리더와 연결 못하면 초기화 실패
syncLimit
: 파티션 팔로워 - 리더 연결할 수 있는 최대 시간 (동기화 제한 시간)- 이 시간 동안 리더와 연결 못하면 동기화 풀림
tickTime
: 밀리초- e.g.
initLimit Time = 20 * 2000ms = 40000ms = 40s
- e.g.
server.{X}={hostname}:{peerPort}:{leaderPort}
X
: 서버 ID (0부터 시작할 필요 ❌, 순차적 부여될 필요 ❌)hostname
: 서버의 호스트명, IP 주소peerPort
: 앙상블 내부 서버들이 통신할때 사용하는 TCP 포트번호leaderPort
: 리더를 선출하는데 사용되는 TCP 포트번호
clientPort
: 클라이언트는 해당 포트로 앙상블에 연결할 수만 있으면 됨- 하지만, 앙상블 멤버들은 peerPort, leaderPort, clientPort 모두 사용해서 서로 통신할 수 있어야함
한 대의 서버에서 주키퍼 앙상블 테스트
localhost:peerPort:leaderPort
- peerPort, leaderPort에 서로 다른 포트를 할당
- 하나의 서버에서 주키퍼 앙상블 테스트 가능
- 각각의 주키퍼 인스턴스에 서로 다른 dataDir, clientPort 할당
- 추가적인
zoo.cfg
파일 생성 필요
# 카프카 설치
# macOS 설치
필자는 macOS 환경에서 실습을 진행했다. homebrew 사용을 선호하지 않아서 카프카 홈페이지의 2.13-2.8.0을 설치했다.
|
|
# 토픽 생성 및 확인
토픽 생성 및 확인
|
|
토픽에 메세지 작성
|
|
토픽에 저장된 메세지 읽기
|
|
CLI 유틸리티 주키퍼 연결 지원 중단
--zookeeper
연결 문자열 지원 중단--bootstrap-server
사용하여 카프카 브로커에 직접 연결- 클러스터 운영중이라면 브로커의
{호스트명}:{포트번호}
사용 가능
# 브로커 설정
- 카프카는 거의 모든 구성을 제어하고 튜닝 가능
- 다만, 특정 활용 사례가 아닌 경우, 바꿀 일이 없는 튜닝 관련 옵션이 다수
- 우선 기본값으로 사용해도 무방
KRaft 모드 설정은 6장 참조
# 핵심 브로커 매개변수
- 단일 서버에서 단독으로 실행되는 브로커라면 상관없음
- 위의 경우를 제외하면 봐야만 하는 브로커의 설정 매개변수들이 있음
- 브로커의 기본적인 설정 담당
- 다른 브로커들과 클러스터 모드로 작동시키려면 변경 필요 🟢
(1) broker.id
- 카프라 브로커의 정숫값 식별자
- default : 0
- 클러스터 안의 각 브로커별로 전부 달라야 함
- 호스트별로 고정된 값을 사용하는 것이 강력하게 권장됨
- e.g.
host1.example.com / host2.example.com
인 경우broker.id = 1 / broker.id = 2
- e.g.
(2) listeners
{프로토콜}://{호스트이름}:{포트}
- e.g.
PLAINTEXT://localhost:9092 , SSL://:9091
- 일반적인 보안 프로토콜이 아니라면
listener.security.protocol.map
재설정 필요
- e.g.
- 호스트이름이
0.0.0.0
인 경우- 모든 네트워크 인터페이스로부터 연결 받게됨
- 호스트이름이
빈값
인 경우- 기본 인터페이스에 대해서만 연결 받게됨
- 1024 미만의 포트번호 사용할 경우
- 루트 권한으로 카프카 실행 필요 🟢
- 권장 ❌
(3) zookeeper.connect
- 브로커의 메타데이터가 저장되는 주키퍼의 위치를 가리킴
- e.g. 로컬호스트의 2181번 포트에서 작동중인 주키퍼를 사용하는 경우
localhost:2181
- e.g. 로컬호스트의 2181번 포트에서 작동중인 주키퍼를 사용하는 경우
{호스트이름}:{포트}/{경로}
호스트이름
: 주키퍼 서버의 호스트이름, IP 주소포트
: 주키퍼 클라이언트 포트 번호/{경로}
: optional, 카프카 클러스터의 chroot 환경으로 사용될 주키퍼 경로- 미지정 시 루트 디렉토리 사용됨
- chroot가 존재하지 않는 경로일 시, 브로커가 시작될 때 자동으로 생성됨
chroot 경로 사용 이유
- 다른 애플리케이션 (다른 카프카 클러스터 포함)과 충돌할 일 없이 주키퍼 앙상블을 공유해서 사용할 수 있기 때문
- 같은 앙상블에 속하는 다수의 주키퍼 서버를 지정하는 것이 좋음
- 특정 서버에 장애 발생 시, 카프카 브로커가 같은 주키퍼 앙상블의 다른 서버에 연결 가능 🟢
(4) log.dirs
- 카프카는 모든 메세지를 로그 세그먼트(log segment) 단위로 묶어서
log.dir
에 지정된 디스크 디렉토리에 저장함 - 다수의 디렉토리 지정 원하는 경우,
log.dirs
사용하는 것이 좋음log.dirs
미 설정시log.dir
사용됨
log.dirs
는 쉼표로 구분된 로컬 시스템 경로의 목록- 1개 이상의 경로 지정 시, 브로커는 가장 적은 수의 파티션이 저장된 디렉토리에 새 파티션을 저장
- 같은 파티션에 속하는 로그 세그먼트는 동일 경로에 저장
- 사용된 디스크 용량 기준이 아닌 저장된 파티션 수 기준으로 새 파티션의 저장 위치를 배정함
- 다수의 디렉토리에 균등한 양의 데이터가 저장되지 않는다는 의미
(5) num.recovery.threads.per.data.dir
- 카프카는 설정 가능한 스레드 풀을 사용하여 로그 세그먼트 관리
- 브로커 정상 시작 시, 각 파티션의 로그 세그먼트 파일 오픈
- 브로커 장애 발생 후 재시작 시, 각 파티션의 로그 세그먼트 검사 후, 잘못된 부분 삭제
- 브로커 종료 시, 로그 세그먼트를 정상적으로 클로즈
- default : 하나의 로그 디렉토리에 하나의 스레드만 사용
- 이 스레드들은 브로커가 시작될 때, 종료될 때만 사용됨
- 작업을 병렬화하기 위해 많은 수의 스레드를 할당해주는 것이 좋음
- 브로커에 많은 파티션이 저장된 경우, 해당 설정에 따라 언클린 셧다운(unclean shutdown) 이후 복구를 위한 재시작 시간이 몇 시간씩 차이가 날 수 있음
- 이 설정값을 잡을 때
log.dirs
에 지정된 로그 디렉토리별 스레드 수임을 명심 - e.g.
num.recovery.threads.per.data.dir = 8, log.dirs에 지정된 경로 수 = 3
- → 전체 스레드 수는 24개
(6) auto.create.topics.enable
- default : 아래의 상황에서 브로커가 토픽을 자동 생성함
- 프로듀서가 토픽에 메세지 작성 시작했을 때
- 컨슈머가 토픽으로부터 메세지 읽기 시작했을 때
- 클라이언트가 토픽에 대한 메타데이터 요청 시
- 문제점 : 카프카에 토픽을 생성하지 않고 존재 여부만을 확인할 방법 ❌
- 토픽 생성을 명시적으로 관리할 경우 해당 값을 false로 설정 가능 🟢
- e.g.
auto.create.topics.enable = false
(7) auto.leader.rebalance.enable
- 모든 토픽의 리더 역할이 하나의 브로커에 집중됨으로써 카프카 클러스터의 균형이 깨지는 순간 발생 가능 🟢
- 해당 설정 활성화 시, 가능한 리더 역할이 균등하게 분산되도록 하여 위 상황 방지
- 파티션의 분포 상태를 주기적으로 확인하는 백그라운드 스레드 시작
leader.imbalance.check.interval.seconds
값으로 주기 설정 가능
- 전체 파티션 중 특정 브로커에 리더 역할이 할당된 파티션 비율이
leader.imbalance.per.broker.percentage
값을 넘기면 파티션의 선호 리더 리밸런싱 발생- 해당 기능은 5장의 선호 리더 선출에서 다시 설명
(8) delete.topic.enable
- 클러스터의 토픽을 임의로 삭제하지 못하게 막을 때
- e.g.
delete.topic.enable = false
- 토픽 삭제 기능 막음
# 파티션 수 결정
파티션은 카프카 클러스터 내부에서 토픽의 크기가 확장되는 방법
- 브로커 추가 시, 클러스터 전체에 걸쳐 메세지 부하가 고르게 분산되도록 파티션 개수를 잡아주는 것이 중요
- 보통
토픽당 파티션 개수
를클러스터 내 브로커의 수
와 맞추거나 배수로 설정- 파티션이 브로커들 사이에 고르게 분산되도록 할 수 있음
- e.g. 10개의 파티션으로 이루어진 토픽이 10개의 호스트로 구성된 카프카 클러스터에서 작동 중이며 각 파티션의 리더 역할이 10개 호스트에 고르게 분산되어있다면 최적의 처리량이 나올 것
- 토픽 여러개 생성 이외에 다른 방법으로 메세지 부하 분산이 가능해서 필수 사항은 아님
파티션 수는 어떻게 결정? 여러가지 사항을 고려하자
- 토픽에 대해 달성하고자 하는 처리량이 대략 어느정도?
- 단일 파티션에 대해 달성하고자 하는 최대 읽기 처리량은 어느정도?
- 1개의 파티션은 항상 1개의 컨슈머만 읽을 수 있음 (컨슈머 그룹 기능 미사용 시에도, 컨슈머는 해당 파티션의 모든 메세지를 읽도록 되어있음)
- 각 프로듀서가 단일 파티션에 쓰기 작업하는 최대 속도에 대해서도 고려할 수 있음
- 다만, 프로듀서가 컨슈머에 비해 훨씬 더 빠른 것이 보통
- 이 작업은 건너뛰어도 괜찮음
키값을 기준으로 선택된 파티션에 메세지를 전송하는 경우, 추후 파티션 추가 시 복잡
- 이 경우 현재의 사용량이 아닌 미래의 사용량 예측값을 기준으로 처리량 계산
- 각 브로커에 배치할 파티션 수, 브로커별 사용 가능 디스크 공간, 네트워크 대역폭 고려
- 과대 추산 피하기
- 각 파티션은 브로커의 메모리와 다른 자원들을 사용함
- 메타데이터 업데이트, 리더 역할 변경 등 여러 부분에서 걸리는 시간 증가하게됨
- 데이터를 미러링 할 예정이라면, 미러링 설정의 처리량 또한 고려 필요
- 미러링 구성에서 큰 파티션이 병목 구간인 경우 많음
- 클라우드 서비스 사용 시, VM이나 디스크에 초당 입출력(IOPS, input/output operations per second) 제한 걸려있는지도 확인 필요
- IOPS 상한선이 설정되어 있을 수 있음
- 파티션 수가 너무 많으면 병렬 처리 때문에 IOPS 양이 증가할 수 있음
결론 : 파티션은 많아야 하지만, 너무 많으면 안된다
- 토픽의 목표 처리량, 컨슈머의 예상 처리량에 대한 추정값이 있다면 필요한 파티션 수 계산 가능
- e.g. 주어진 토픽을 읽는 속도가 초당 1GB를 원해요
- 컨슈머 1개가 초당 50MB만 처리가 가능한 상황
- 그렇다면 최소한 20개의 파티션이 필요하다고 예측 가능
- 20개의 컨슈머가 동시에 하나의 토픽을 읽어서 초당 1GB 읽기 가능
- e.g. 주어진 토픽을 읽는 속도가 초당 1GB를 원해요
- 상세 정보 없는 경우
- 링크드인 경험 상, 디스크 내부에 저장되어 있는 파티션의 용량을 6GB 미만으로 유지하는 것이 대체로 결과가 좋았음
- 작은 크기에서 점진적 확장이 반대보다 더 쉽다
# 토픽별 기본값
- 카프카 브로커 설정 → 새로 생성되는 토픽에 적용되는 수많은 설정의 기본값 지정
- 토픽별 설정값을 재정의하고 싶으면 관리툴 사용 필요. 해당 내용은 12장에서 학습
(1) num.partitions
- 새로운 토픽이 생성될 때 몇 개의 파티션을 갖게 되는지 결정
- default : 1
- 자동 토픽 생성 기능이 활성화되어 있을 때 사용됨
- 자동 토픽 생성 기능 역시 default : true
- 토픽의 파티션 개수 늘리기는 🟢 줄이기는 불가능 ❌
- 토픽이
num.partitions
에 지정된 것보다 더 적은 수의 파티션을 가져야 한다 → 직접 토픽을 생성할 필요가 있다
- 토픽이
(2) default.replication.factor
- 자동 토픽 생성 기능 활성화 시, 새로 생성되는 토픽의 복제 팩터를 결정함
- 아래의 설정 값은 하드웨어 장애 등 카프카 외부 요인으로 인한 장애가 발생하지 않아야 하는 카프카 클러스터를 운영하는 상황에서의 권장사항
- 복제 팩터 값은
min.insync.replicas
설정값보다 최소한 1 이상 크게 잡아줄 것을 강력 권장 - 복제 팩터 값을
min.insync.replicas
설정값보다 2 큰 값으로 잡는 경우- 내고장성 있는 설정 원함 + 충분한 하드웨어를 사용할 수 있는 충분히 큰 울러스터 운영중일 때
- 이것을 보통 RF++ 라고 함
- 레플리카 셋 안에 일부러 정지시킨 레플리카, 예상치 않게 정지된 레플리카가 동시에 하나씩 발생해도 장애가 발생하지 않기 때문에 권장됨
- 즉, 일반적인 클러스터의 경우 파티션별로 최소한 3개의 레플리카를 가져야 한다는 이야기
- e.g. 네트워크 스위치나 디스크 같은 하드웨어에 장애 발생 시, 혹은 카프카나 운영체제를 롤링 업데이트 하는 중에 문제가 발생해도 적어도 1개의 레플리카는 정상 작동 중이라는 것을 보장 가능
(3) log.retention.ms
- 카프카가 얼마나 메세지를 보존해야 하는지 지정할 때 사용하는 설정 (시간 기준 설정)
- default :
log.retention.hours = 168
을 보통 사용 → 168시간 (1주일)log.retention.ms
→ 가장 권장 🟢log.retention.minutes
log.retention.hours
- 1개 이상의 설정이 정의된 경우 더 작은 단위 설정값이 우선순위 가짐
log.rentention.ms
에 설정된 값은 언제나 적용됨을 보장할 수 있음. 그래서 권장됨
시간 기준 보존, 마지막 수정 시각
- 시간 기준 보존
- 디스크에 저장된 각 로그 세그먼트 파일의 마지막 수정 시각(mtime) 기준으로 작동
- 이 값은, 해당 로그 세그먼트가 닫힌 시각을 의미
- 이 값은, 해당 파일에 저장된 마지막 메세지의 타임스탬프를 의미
- 하지만, 관리 툴을 사용하여 브로커 간 파티션을 이동시킨 경우 이 값은 정확하지 않음
- → 파티션이 지나치게 오래 보존되는 결과 초래 가능
(4) log.retention.bytes
- 카프카가 메세지를 보존할 수 있는 용량 (크기 기준 설정)
- 파티션 단위로 적용됨
- e.g. 8개의 파티션을 가진 토픽,
log.retention.bytes = 1GB
→ 토픽 최대 저장 용량 8GB
- e.g. 8개의 파티션을 가진 토픽,
- 모든 보존 기능은 토픽 단위가 아닌 파티션 단위로 작동함
log.retention.bytes
설정 사용중인 상태에서 토픽의 파티션 수를 증가 → 보존되는 데이터의 양도 함께 늘어난다는 의미
log.retention.bytes = -1
- 데이터 영구 보존
크기와 시간을 기준으로 보존 설정
log.retention.bytes
,log.retention.ms
두 설정 모두 준 경우
- 하나의 조건만 성립해도 메세지가 삭제될 수 있음
- 의도치 않은 데이터 유실 방지를 위해 크기 기준 설정 / 시간 기준 설정 중 하나만 선택하기를 권장
(5) log.segment.bytes
log.retention.bytes
,log.retention.ms
는 로그 세그먼트에 적용되는 로그 보존 설정- → 메세지 각각에 적용되는 것이 아닙니다 !
- 카프카 브로커에 쓰여진 메세지는 해당 파티션의 현재 로그 세그먼트의 끝에 추가됨
- 로그 세그먼트 크기가
log.segment.bytes
에 지정된 크기에 가까워졌음 - 브로커는 기존 로그 세그먼트를 닫고 새로운 로그 세그먼트를 염
- 로그 세그먼트가 닫히기 전까지 만료/삭제의 대상이 되지 않음
- 로그 세그먼트 크기가
- default : 1GB
- 작은 로그 세그먼트 크기
- 더 자주 닫고 새로 할당한다는 의미
- 디스크 쓰기의 전체적인 효율성 감소를 의미
토픽에 메세지가 뜸하게 주어지는 상황
- 로그 세그먼트 크기 조절이 중요할 수 있음
- e.g. 토픽에 들어오는 메세지가 하루 100MB +
log.segment.bytes
기본값 1GB
- 세그먼트 하나 채울때까지 10일 걸림
- 로그 세그먼트가 닫히기 전까지 메세지는 만료되지 않음
log.retention.ms = 604800000(1주일)
로 잡힌 경우- 닫힌 로그 세그먼트가 만료될 때까지 실제로는 최대 17일치 메세지가 저장되어 있을 수 있음
- 로그 세그먼트 닫힐 때까지 채우기 10일 + 보존기간 7일
타임스탬프 기준 오프셋 찾기
- 로그 세그먼트 크기는 타임스탬프 기준 오프셋 찾는 기능에도 영향 끼침
- (1) 클라이언트가 특정 타임스탬프 기준으로 파티션의 오프셋 요청
- (2) 카프카는 해당 시각에 쓰여진 로그 세그먼트 찾음
- (3) 로그 세그먼트 파일 생성 시각 + 마지막 수정 시각을 이용하여 작업
- 주어진 타임스탬프보다 생성된 시각은 더 이름
- 마지막으로 수정된 시각은 더 늦은 파일을 찾음
- (4) 로그 세그먼트의 맨 앞에 있는 오프셋이 응답으로 리턴됨
- 맨 앞에 있는 오프셋은 로그 세그먼트 파일의 이름이기도 함
(6) log.roll.ms
- 파일이 닫혀야 할 때까지 기다리는 시간을 지정하는 매개변수
- 로그 세그먼트 파일이 닫히는 과정을 해당 매개변수로도 제어 가능하다는 의미
- default : 설정 X
- 기본적으로 세그먼트 파일을 닫는 작업은 크기 기준으로만 이루어지는 것이 기본값
시간 기준 세그먼트 사용 시 디스크 성능
- 다수의 로그 세그먼트가 동시에 닫힐 때, 디스크 성능에 대한 고려 필요
- 여러 개의 파티션이 로그 세그먼트 크기 제한에 도달하지 못하는 경우 발생 가능
- 브로커가 시작되는 시점부터 시간제한이 계산됨
- 크기가 작은 파티션을 닫는 작업 역시 한꺼번에 이루어지기 때문
(7) min.insync.replicas
- default : 1
- 데이터 지속성 위주로 클러스터 설정 시, 해당 값을 2로 잡는 경우
- 최소한 2개의 레플리카가 최신 상태로 프로듀서와 동기화되도록 가능 🟢
- 프로듀서의 ack 설정을
all
로 잡아주는 것과 함께 사용됨 - 프로듀서의 쓰기 작업이 성공하기 위해 최소한 두 개의 레플리카 (리더 하나, 팔로워 하나) 가 응답하도록 할 수 있음
- 이는 아래 상황에서 데이터 유실 방지 가능
- (1) 리더가 쓰기 작업에 응답
- (2) 리더에 장애 발새
- (3) 리더 역할이 최근에 성공한 쓰기 작업 내역을 복제하기 전의 다른 레플리카로 옮겨짐
min.insync.replicas
설정 ❌인 경우- 프로듀서는 쓰기 작업이 성공했다고 착각
- 실제로는 메세지가 유실
min.insync.replicas
설정값 높게 잡은 경우- 오버헤드 발생하여 성능 감소하는 부작용 발생
- 몇 개의 메세지 유실 정도는 괜찮고, 높은 처리량을 받아내야 하는 클러스터의 경우
- 기본값인 1에서 변경하지 않는 것을 권장
(8) message.max.bytes
- 카프카 브로커는 쓸 수 있는 메세지 최대 크기를 제한함
- default : 1,000,000 (1MB)
- 프로듀서가
message.max.bytes
보다 큰 크기의 메세지 보내려고 시도 → 브로커는 메세지를 거부하고 에러 리턴 - 브로커에 설정된 모든 바이트 크기와 마찬가지로, 압축된 메세지의 크기를 기준으로 함
- 프로듀서는 압축된 결과물이
message.max.bytes
보다 작기만 하면 압축 전 기준 이 값보다 훨씬 큰 메세지도 보낼 수 있는 것
- 프로듀서는 압축된 결과물이
- 허용 가능 메세지 크기 증가 → 성능에 큰 영향
- 메세지가 커지는 만큼 네트워크 연결, 요청 처리하는 브로커 스레드의 요청당 작업 시간 증가
- 디스크에 써야하는 크기 증가 → I/O 처리량에 영향 끼침
- 개체 저장소(blob store), 계층화된 저장소(tiered storage) 솔루션으로 디스크 용량 문제 해결할 수 있음
메세지 크기 설정 조정
- 카프카 브로커에 설정되는 메세지 크기
- 컨슈머 클라이언트의
fetch.message.max.bytes
설정과 맞아야 함fetch.message.max.bytes
<message.max.bates
인 경우
- 컨슈머는 지정된
fetch.message.max.bytes
값보다 더 큰 메세지를 읽는데 실패- 읽기 작업 진행 중단
- 이는 클러스터 브로커의
replica.fetch.max.bytes
설정에도 동일하게 적용됨
# 하드웨어 선택
- 카프카 자체는 특정한 하드웨어 구성 요구 ❌
- 다만 성능 때문에 디스크 처리량, 디스크 용량, 메모리, 네트워크, CPU 감안 필요
- 카프카를 매우 크게 확장할 경우
- 업데이트 되어야 할 메타데이터의 양 때문에 하나의 브로커가 처리할 수 있는 파티션의 수에도 제한 생길 수 있음 🟢
# 디스크 처리량
브로커 디스크의 처리량
- 로그 세그먼트 저장
- 클라이언트의 성능에 가장 큰 영향을 끼침
- 프로듀서 클라이언트가 메세지 전송을 성공했다고 결론 내리기 이전, 최소한 1개 이상의 브로커가 메세지가 커밋되었다고 응답을 보낼 때까지 대기하게 됨
- 디스크 쓰기 (↑) → 쓰기 지연 (↓)
여러 저장장치 선택 가이드
- SSD : 탐색과 접근에 들어가는 시간 압도적으로 짧음. 최고의 성능
- HDD : 더 싸고 같은 가격에 더 많은 용량 제공
- 데이터 디렉토리 여러 개로 잡기
- RAID (Redundant Array of Independent Disks) 구성을 통해 브로커에 여러 대의 HDD를 사용하여 성능 향상시키기 가능
- SAS (Serial Attached SCSI), SATA (Serial ATA) 같은 특정 드라이브 기술, 드라이브 컨트롤러의 성능 등도 처리량에 영향 끼침
- 많은 수의 클라이언트 연결을 받아내야하는 경우 → SSD 승
- 자주 쓸 일이 없는 데이터를 굉장히 많이 저장해야 하는 클러스터의 경우 → HDD 드라이브 승
# 디스크 용량
- 특정 시점에 얼마나 많은 메세지들이 보존되어야 하는지에 따라 결정
- e.g. 브로커가 하루에 1TB 트래픽 받을 것으로 예상 + 받은 메세지 1주일간 보존
- 로그 세그먼트를 저장하기 위한 저장 공간이 최소 7TB 필요
- 트래픽 변동/증가 대비 예비 공간, 저장해야 할 다른 파일 감안하여 최소 10% 가량 오버헤드 고려
디스크 저장 용량은 카프카 클러스터의 크기를 변경, 확장하는 시점에 고려할 중요한 요소
- 클러스터에 들어오는 전체 트래픽 → 토픽별 다수의 파티션을 잡아서 클러스터 전체에 균형있게 분산 가능 🟢
- 단일 브로커의 용량이 충분하지 못하면 → 브로커 추가하여 전체 용량 증대 가능 🟢
- 필요한 디스크 용량은 클러스터에 설정된 복제 방식에 따라서도 달라짐
# 메모리
프로듀서가 막 추가한 메세지를 바로 뒤에서 쫓아오는 식으로 카프카 컨슈머가 파티션의 맨 끝에서 메세지를 읽는 것이 보통
- 최적의 작동 : 시스템의 페이지 캐시에 저장된 메세지들을 컨슈머가 읽어오는 것
- 브로커가 디스크로부터 메세지를 다시 읽어오는 것보다 더 빠르게 읽어오는 것
- 시스템에 페이지 캐시로 사용할 메모리를 추가 할당
- 컨슈머 클라이언트 성능 향상 (↑)
카프카 자체는 JVM에 많은 힙 메모리를 필요로 하지 않음
- e.g. 1s 당 150,000개의 메세지에 200MB의 데이터 속도를 처리하는 브로커
- 5GB 힙 정도 사용
- 시스템 메모리의 나머지 영역은 페이지 캐시로 사용됨
- 시스템이 사용중인 로그 세그먼트를 캐시하도록 함 → 카프카의 성능 향상 (↑)
- 카프카를 하나의 시스템에서 다른 애플리케이션과 함께 운영하는 것을 권장하지 않는 이유
- 페이지 캐시를 나눠서 쓰게 됨 → 카프카 컨슈머 성능 저하 (↓)
# 네트워크
사용 가능한 네트워크 대역폭 → 카프카가 처리할 수 있는 트래픽 최대량 결정
- 디스크 용량과 함께 클러스터의 크기를 결정하는 가장 결정적 요인
카프카 특유의 네트워크 불균형 문제
- 카프카가 다수의 컨슈머를 동시 지원함
- 이때 인입되는 네트워크 사용량, 유출되는 네트워크 샤용량 사이에 불균형 생김
- e.g. 프로듀서가 주어진 토픽에 초당 1MB 쓰기 작업 중
- 해당 토픽에 컨슈머가 다수 붙음으로써 유출되는 네트워크 사용량 훨씬 증가
- 클러스터 내부의 복제, 미러링 등 요구 조건이 많아짐
- 네트워크 인터페이스가 포화상태에 빠진 경우
- 클러스터 내부 복제작업이 밀려서 클러스터가 취약한 상태에 빠짐
- 네트워크 문제 방지 위해 최소한 10GB 이상 처리 가능한 네트워크 인터페이스 카드(NIC) 사용 권장