🥞 BE
home

Ch5. 카프카 운영과 모니터링

Date
2025/01/23
Category
Data Engineering
Tag
Apache Kafka
Detail
실전 카프카 Study
목차
개발 관련 모든 서비스 운영에서 모니터링은 중요하다. 초기 구성 단계부터 관리자가 꼼꼼히 단일 장애 지점을 제거하고 클러스터를 구성한다면, 더욱 안정적인 클러스터를 운영할 수 있다. 이를 위해 고려할 사항들을 알아보자.

1. 주키퍼 구성

1.1. 주키퍼 서버 수량

주키퍼는 기본적으로 쿼럼(과반수) 구성을 기반으로 동작하므로 반드시 홀수로 구성해야 함. 최소 수량은 3개.
운영환경에서 카프카의 사용량이 높지 않을 경우 - 3대로 구성
핵심 중앙 데이터 파이프라인으로 카프카를 활용중인 경우 - 5대로 구성

1.2. 주키퍼 하드웨어

메모리 크기 : 4~8G
디스크 : 240G || 480G SSD(쓰기 성능 up)

1.3. 주키퍼 배치

물리적 서버 - 분산 배치
클라우드 환경에서도 가용영역 2~3개 나눠서 운영 권장

2. 카프카 구성

2.1. 카프카 서버 수량

카프카는 주키퍼와 달리 쿼럼 방식의 구성이 필요하지 않음. 따라서 반드시 홀수일 필요는 X.
but, 카프카에서 추천하는 안정적인 replication factor 수인 3으로 topic을 구성하기 위해서, 최소 3대의 broker가 필요.

2.2. 카프카 하드웨어

producer, consumer의 처리량을 높이기 위해 배치와 압축 기능을 많이 사용 → 주키퍼와 달리 카프카의 CPU 사용률은 높은 편.
CPU : 코어 수가 많으면 좋음
메모리 : 최소 32GB이상
디스크 : SATA를 선택해도 됨 (순차적 쓰기), 4TB 용량 이상의 디스크로 선정하는 것을 추천
네트워크 : 브로커 한 대당 네트워크 사용량 비율 50% 넘지 않도록 분산.

2.3. 카프카 배치

주키퍼와 동일. multi AZ

3. 모니터링 구성

1.
애플리케이션 로그 분석
2.
JMX 활용 브로커 메트릭 정보 분석

3.1. 애플리케이션 카프카 로그 모니터링

카프카는 애플리케이션 로그 관리를 위해 Java 기반 로깅 유틸리티인 log4j를 활용.
로그 레벨
설명
TRACE
DEBUG보다 상세한 로그를 기록
DEBUG
내부 애플리케이션 상황에 대한 로그를 기록(INFO 보다 상세한 로그)
INFO
로그 레벨의 기본값. 일반적인 정보 수준의 로그를 기록
WARN
INFO보다 높은 개념. 경고 수준의 로그를 기록
ERROR
경고 수준을 넘어 런타임 에러나 예상치 못한 에러 로그를 기록
FATAL
로그 레벨 중 최종 단계. 심각한 오류로 인한 애플리케이션 중지 등의 로그를 기록
아래로 갈수록 상위 로그 레벨이며, 위로 갈수록 로그가 상세해짐. 설정된 레벨 기준 상위 로그 레벨까지 모두 출력.
카프카에서는 INFO 수준 로그 레벨이 default. 만약 DEBUG 레벨로 바꾸고 싶다면?
sudo vi /usr/local/kafka/config/log4j.properties
log4j.logger.kafka=DEBUG log4j.logger.org.apache.kafka=DEBUG
Plain Text
복사
이후 sudo systemctl restart kafka-server 로 로그 레벨 적용
하위 로그 레벨로 변경 시 → 더 많은 로그 기록 → 여유 디스크 용량을 꼭 확인할 것
카프카 애플리케이션의 로그 파일
로그 파일 이름
설명
server.log
브로커 설정 정보와 정보성 로그 등을 기록
state-change.log
컨트롤러로부터 받은 정보를 기록
kafka-request.log
클라이언트로부터 받은 정보를 기록
log-cleaner.log
로그 컴팩션 동작들을 기록
controller.log
컨트롤러 관련 정보를 기록
kafka-authorizer.log
인증과 관련된 정보를 기록

3.2. JMX를 이용한 카프카 메트릭 모니터링

현재 카프카 로그이외에도, 카프카 클러스터의 상태 및 이상 유무를 확인해야 함.
JMX(Java Management eXtensions)는 자바로 만든 애플리케이션의 모니터링을 위한 도구를 제공하는 Java API로서, MBean(Managed Bean)이라는 객체로 표현됨.
1.
카프카 broker에 JMX 포트 오픈
systemd의 환경 변수 옵션을 추가하는 방식. 이미 설치 과정에서 추가되어 있음.
cat /usr/local/kafka/config/jmx
JMX_PORT=9999
Plain Text
복사
netstat -ntl | grep 9999LISTEN 여부 확인
2.
프로메테우스 설치 (메트릭 수집)
프로메테우스 - 메트릭 기반 오픈소스 모니터링 시스템. 데이터 모델과 쿼리로 custom한 메트릭 모니터링.
책에서는 docker 환경에 prometheus 올려서 설치함. 아래 yml 파일도 책 기준
# prometheus config global: scrape_interval: 5s evaluation_interval: 5s scrape_configs: - job_name: 'peter-jmx-kafka' static_configs: - targets: - peter-kafka01.foo.bar:7071 - peter-kafka02.foo.bar:7071 - peter-kafka03.foo.bar:7071 - job_name: 'peter-kafka-nodes' static_configs: - targets: - peter-kafka01.foo.bar:9100 - peter-kafka02.foo.bar:9100 - peter-kafka03.foo.bar:9100 - job_name: 'peter-kafka-exporter' static_configs: - targets: - peter-kafka01.foo.bar:9308 - peter-kafka02.foo.bar:9308 - peter-kafka03.foo.bar:9308
YAML
복사
prometheus.yml
sudo docker run -d --network host -p 9090:9090 -v / etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml --name prometheus prom/prometheus
3.
그라파나 설치 (대시보드)
sudo docker run -d --network host -p 3000:3000 --name grafana grafana/grafana:7.3.7
4.
익스포터 설치
프로메테우스의 모니터링 방식은 push가 아닌 pull 방식. 따라서 모니터링하고자 하는 대상 서버에 자신의 메트릭 정보를 보여줄 수 있는 익스포터(Exporter)를 설치해야 함.
익스포터 - 애플리케이션에서 수집되는 메트릭들을 프로메테우스가 인식할 수 있는 형태로 나타내는 에이전트
따라서 익스포터를 설치한 후, 대상 서버 주소(http://peter-kafka01.foo.bar:9100/metrics)로 접근하면, 익스포터에서 보여주는 다양한 메트릭 정보를 확인 가능.
디렉토리 생성해서 위 링크에서 익스포터 파일 복사 후, 복사한 yml 파일에서 앞서 설정해둔 JMX 포트 9999인지 확인.
hostPort: 127.0.0.1:9999 ssl: false rules: - pattern: ".*"
YAML
복사
jmx_prometheus_httpserver.yml
이제 익스포터 실행.
[Unit] Description=JMX Exporter for Kafka After=kafka-server.target [Service] Type=simple Restart=always ExecStart=/usr/bin/java -jar /usr/local/jmx/jmx_prometheus_httpserver-0.13.1-SNAPSHOT-jar-with-dependencies.jar 7071 /usr/local/jmx/jmx_prometheus_httpserver.yml [Install] WantedBy=multi-user.target
YAML
복사
jmx-exporter.service
systemd를 이용해 실행해야 함. Linux에서 systemd 변경이 생긴 경우는 꼭 daemon-reload 해줘야 함.
sudo cp kafka2/chapter7/jmx-exporter.service /etc/systemd/system
sudo systemctl daemon-reload
이후 실행.
sudo systemctl start jmx-exporter
JMX 익스포터는 broker 한 대에 설치하는 것이 아니라 카프카 클러스터 내 모든 broker에 설치해야 함.
이제 broker 서버의 하드웨어 리소스 모니터링을 위해 노드 익스포터(Node Exporter)도 설치. 노드 익스포터는 서버에서 제공하는 CPU, 메모리, 디스크, 네트워크 등의 리소스 사용량을 수집하는 역할.
wget 명령어로 모든 브로커에 다운로드
wget https://github.com/prometheus/node_exporter/releases/download/v1.0.1/node_exporter-1.0.1.linux-386.tar.gz
압축 해제
sudo tar zxf node_exporter-1.0.1.linux-386.tar.gz -C /usr/local/
심볼릭 링크 걸어줌
sudo ln -s /usr/local/node_exporter-1.0.1.linux-386 /usr/local/node_exporter
다시 systemd 설정해주고
sudo cp kafka2/chapter7/jmx-exporter.service /etc/systemd/system
sudo systemctl daemon-reload
이후 실행.
sudo systemctl start node-exporter
노드 익스포터도 broker 한 대에 설치하는 것이 아니라 카프카 클러스터 내 모든 broker에 설치해야 함.
이제 프로메테우스를 재시작해서, 아까 prometheus.yml 복사한 내용을 반영. "status": "success" 가 확인되었다면, 그라파나 3000번 포트로 접속해서 대시보드 구성해주면 끝.

JMX 모니터링 지표

카프카 모니터링을 위해 JMX에서 제공하는 지표는 매우 많으며, 주요 메트릭은 대부분 대시보드에 추가되어 있음. 아래 표에서 JMX 메트릭의 주요 항목과 각 항목별 MBean의 유형과 의미, 주의사항들을 정리.
JMX 메트릭 항목
MBean 사용 유형
설명
TopicCount
kafka.controller:type=kafkaController,name=GlobalTopicCount
카프카 클러스터 전체의 토픽 개수를 나타냄
PartitionCount
kafka.controller:type=kafkaController,name=GlobalPartitionCount
카프카 클러스터 전체의 파티션 개수를 나타냄
ActiveControllerCount
kafka.controller:type=kafkaController,name=ActiveControllerCount
카프카 클러스터 내 컨트롤러 수를 나타냄. 클러스터 내에는 반드시 1개의 컨트롤러가 존재해야함. 알람을 설정해두면, 1이 아닌 경우 알람이 발생함
UnderReplicatedPartitions
kafka.server:type=ReplicaManager,nameUnderReplicatedPartitions
카프카 클러스터 내에서 복제가 되지 않은 파티션 수를 나타냄. 알람을 설정해두면, 0이 아닌 경우 알람이 발생됨. 오프라인 파티션 수를 나타내는 지표도 있지만,해당 지표와 거의 동일하게 알람이 감지되어 이 지표만 모니터링해도 운영하는 데 큰 무리는 없음.오프라인 파티션 모니터링이 필요하다면, kafka.controller:type=KafkaController,name=OfflinePartitionsCount를 참고하길 바람
UnderMinIsrPartitionCount
kafka.server:type=ReplicatedManager, name=UnderMinIsrPartitionCount
안정적인 메시지 전송을 위해 유지해야 하는 최소 ISR 수를 지정하는 경우가 있음. 유지해야 하는 최소 ISR수보다 작은 수를 나타냄. 알람을 설정해두면 0이 아닌 경우 알람이 발생됨
MessageInPerSec
kafka.server:type=BrokerTopicMetics,name=MessageInPerSec
브로커로 전송되는 초당 메시지 수를 나타냄
BytesInpPerSec
kafka.server:type=BrokerTopicMetics,name=BytesInPerSec
브로커로 전송되는 초당 바이트 수를 나타냄
BytesOutPerSec
kafka.server:type=BrokerTopicMetics,name=BytesOutPerSec
브로커에서 나가는 초당 바이트 수를 나타냄. 일반적으로 브로커로 들어오는 바이트 수보다 나가는 바이트 수가 더 많음. 프로듀서는 하나의 토픽으로 메시지를 전송하지만, 카프카의 특성상 해당 토픽을 컨슘하는 컨슈머들은 다수가 존재할 수 있으므로 나가는 바이트 수가 더 많기 때문
RequestPerSec
kafka.network:type=ReplicatedMetrics,name=RequestsPerSec,request={Produce|FetchConsumer|FetchFollower}
프로듀서, 컨슈머, 팔로워들의 요청 비율을 나타냄
LeaderCount
kafka.network:type=ReplicaManager,name=LeaderCount
브로커가 갖고 있는 리더의 수를 나타냄. 카프카는 리더가 읽고 쓰기를 처리하므로, 클러스터 전체에 고르게 분산시켜서 브로커들이 균등하게 처리하게 해야 함
PartitionCount
kafka.network:type=ReplicaManager,name=PartitionCount
브로커가 갖고 있는 파티션 수를 나타냄. 파티션 수 역시 클러스터 전체에 고르게 분산시켜서 브로커들이 균등하게 처리하게 해야 함
IsrShrinkPerSec
kafka.network:type=ReplicaManager,name=IsrShrinkPerSec
브로커가 다운된다거나 리플리케이션 동작에 문제가 발생하면, ISR이 축소되는 현상이 발생함. 따라서 파티션의 리플리케이션 동작에 문제가 있는지 유무 등을 확인할 떄 사용하는 지표임. 알람을 성정해두면, 0보다 큰 경우 알람이 발생됨. 브로커가 장애에서 복구되거나 리플리케이션 동작이 정상화될 때 ISR이 화장되는데, 이 지표는 kafka.network:type=ReplicaManager,name=IsrExpandPerSec값을 통해 확인할 수 있음
RequestQueueSize
kafka.network:type=RequestChannel,name=RequestQueueSize
요청 큐의 크기를 나타냄. 큐의 크기가 크다는 것은 처리되지 못하는 요청들이 많다는 의미
ResponseQueueSize
kafka.network:type=RequestChannel,name= ResponseQueueSize
요청 큐의 크기를 나타냄. 큐의 크기가 크다는 것은 처리되지 못하는 응답들이 많다는 의미
RequestHandlerAvgIdlePercent
kafka.network:type=KafkaRequestHandlerPool,name= RequestHandlerAvgIdlePercent
요청 핸들러 스레드가 유휴 상태인 평균 시간을 나타냄. 이 값이 0이면 모든 리소스가 사용된 것이고, 1이면 모든 리소스를 가용할 수 있는 상태를 나타냄
NetworkProcessorAvgIdlePercent
kafka.network:type=SocketServer,name=NetworkProcessorAvgIdlePercent
네트워크 프로세서 스레드가 유휴 상태인 평균 시간을 나타냄. 이 값이 0이면 모든 리소스가 사용된 것이고, 1이면 모든 리소스를 가용할 수 있는 상태를 나타냄
RequestQueueTimeMs
kafka.network:type=RequestMetrics,name=RequestQueueTimeMs,request={produce|FetchConsumer|FetchFollower}
요청 큐에서의 대기시간을 나타냄
LocalTimeMs
kafka.network:type=RequestMetrics,name=LocalTimeMs,request={produce|FetchConsumer|FetchFollower}
리더에서 요청을 처리하는 시간을 나타냄
RemoteTimeMs
kafka.network:type=RequestMetrics,name=RemoteTimeMs,request={produce|FetchConsumer|FetchFollower}
팔로워들이 기다리는 시간을 나타내며, 프로듀스 옵션에서 acks=all 등을 사용하면 시간이 길어질 수 있음
ResponseQueueTimeMs
kafka.network:type=RequestMetrics,name=ResponseQueueTimeMs,request={produce|FetchConsumer|FetchFollower}
응답 큐에서의 대기시간을 나타냄
ResponseSendTimeMs
kafka.network:type=RequestMetrics,name=ResponseSendTimeMs,request={produce|FetchConsumer|FetchFollower}
응답을 보내는 시간을 나타냄

Reference