Engineering Note
Kafka Client Metrics는 관측의 빈틈을 메울 수 있을까
KIP-714로 도입된 Kafka 클라이언트 원격 메트릭 수집의 구조, 지원 메트릭, 설정 방법, 그리고 운영 현실에서의 한계를 정리합니다.
Kafka를 운영할 때 broker 메트릭과 consumer lag는 늘 중요한 출발점입니다. broker는 요청 지연, 처리량, quota, 네트워크, partition 상태를 보여주고, consumer lag는 consumer group이 topic을 얼마나 따라가고 있는지 알려줍니다.
하지만 이 둘만으로는 클라이언트 내부를 보기 어렵습니다.
producer의 buffer에서 record가 오래 머무는지, consumer가 poll loop에서 얼마나 idle한지, rebalance가 클라이언트 쪽에서 얼마나 자주 길어지는지, 특정 client version이나 client.id에서만 request latency가 튀는지 같은 질문은 broker 메트릭만으로는 답하기 어렵습니다. 그래서 많은 팀은 애플리케이션마다 JMX, Micrometer, OpenTelemetry, custom exporter를 붙여 client-side metric을 따로 모읍니다.
KIP-714: Client metrics and observability는 이 문제를 Kafka protocol 안으로 끌어온 시도입니다. Kafka 3.7.0에서 소개된 이 기능은 broker가 클라이언트에게 어떤 메트릭을 보낼지 구독 정보를 내려주고, 지원 클라이언트가 broker로 메트릭을 push하는 구조를 제공합니다. Kafka 4.0에서는 KIP-1076으로 Kafka Streams 같은 애플리케이션 레벨 메트릭까지 확장하는 방향도 추가되었습니다.
좋은 방향입니다. 문제는 “지원되는 클라이언트”와 “운영 환경에서 실제로 돌아가는 모든 클라이언트” 사이에 간격이 크다는 점입니다.
이 글은 KIP-714의 기능 개요, 도입 배경, 수집 가능한 메트릭, 설정 흐름을 정리한 뒤, 왜 이 기능만으로 Kafka client observability 전략을 바꾸기에는 아직 조심스러운지 설명합니다.
먼저 가져갈 결론
KIP-714을 이해할 때는 다음 다섯 가지가 중요합니다.
- broker가 client metric subscription을 관리합니다.
- 지원 클라이언트는
GetTelemetrySubscriptions로 구독 정보를 받고PushTelemetry로 메트릭을 보냅니다. - broker는 받은 payload를 직접 분석하기보다 broker-side telemetry plugin을 통해 외부 metrics backend로 넘깁니다.
- producer, consumer, admin client의 연결, request latency, throttle, queue, poll, rebalance 같은 표준 메트릭을 대상으로 합니다.
- 효과는 결국 “얼마나 많은 실제 클라이언트가 이 기능을 지원하는 버전으로 올라왔는가”에 달려 있습니다.
한 줄로 줄이면 이렇습니다.
KIP-714는 좋은 중앙 수집 표준이지만,
운영 현실에서는 전체 관측이 아니라 지원 클라이언트의 부분 관측에 가깝습니다.
왜 클라이언트 메트릭이 필요했나
Kafka broker는 클러스터 관점의 상태를 잘 보여줍니다. 어느 broker가 바쁜지, request queue가 밀리는지, produce/fetch 요청이 느려지는지, leader election이나 under-replicated partition이 생기는지 같은 신호는 broker 메트릭으로 읽을 수 있습니다.
하지만 Kafka 문제는 broker 안에서만 생기지 않습니다.
예를 들어 producer가 갑자기 느려졌다고 해봅시다. broker request latency가 높아진 것인지, application thread가 record를 늦게 넣는 것인지, batch가 충분히 모이지 않는 것인지, client buffer가 찼는지, broker quota 때문에 throttle을 받는지에 따라 대응이 달라집니다.
consumer도 마찬가지입니다. consumer lag가 증가할 때 원인은 다양합니다.
- poll loop가 느린가?
- 처리 시간이 긴가?
- rebalance가 반복되는가?
- fetch latency가 높아졌는가?
- commit이 밀리는가?
- 애플리케이션이 record를 가져와놓고 내부 queue에서 오래 붙잡고 있는가?
이 질문들은 broker 밖, 즉 client process 안의 상태와 연결됩니다. 그래서 KIP-714의 도입 배경은 타당합니다. Kafka 운영자가 클라이언트 팀마다 별도 계측을 요청하지 않아도, 클러스터가 표준화된 방식으로 일부 client-side metric을 요청하고 수집할 수 있으면 troubleshooting 시작점이 훨씬 좋아집니다.
구조는 pull이 아니라 subscription 기반 push에 가깝다
이 기능을 “broker가 클라이언트 메트릭을 원격으로 긁어온다”라고 말하기 쉽지만, 실제 감각은 subscription 기반 push에 더 가깝습니다.
흐름은 대략 이렇습니다.
- 운영자가 broker에 client metrics subscription을 설정합니다.
- 지원 클라이언트가 broker에
GetTelemetrySubscriptions요청을 보냅니다. - broker는 해당 client에 적용되는 메트릭 prefix, push interval, subscription id, client instance id를 응답합니다.
- 클라이언트는 지정된 interval에 맞춰
PushTelemetry요청으로 메트릭 payload를 보냅니다. - broker의 telemetry plugin은 받은 payload를 OpenTelemetry Collector, time-series database, vendor backend 같은 외부 시스템으로 전달합니다.
중요한 점은 broker 기본 설정만으로 자동 수집이 시작되지 않는다는 것입니다. KIP-714은 client 쪽에서는 opt-out에 가까운 방향을 목표로 하지만, broker 쪽에서는 명시적인 opt-in입니다. broker에 telemetry를 처리할 plugin이 있어야 하고, CLIENT_METRICS resource에 subscription도 설정해야 합니다.
또 하나의 조건은 KRaft입니다. KIP-714의 client metrics config resource는 ZooKeeper 저장을 새로 구현하지 않고 KRaft를 전제로 설계되었습니다. 아직 ZooKeeper 기반 cluster를 운영 중이라면 이 기능은 단순한 설정 추가가 아니라 cluster 운영 모델과도 연결됩니다.
어떤 메트릭을 볼 수 있나
KIP-714은 모든 Kafka client metric을 무작정 표준화하지 않습니다. 대신 여러 클라이언트 구현체가 공통으로 이해하기 쉬운 standard metric과, 지원 클라이언트라면 반드시 제공해야 하는 required metric 개념을 둡니다.
대표적으로 볼 수 있는 신호는 다음과 같습니다.
| 영역 | 예시 메트릭 | 읽을 수 있는 것 |
|---|---|---|
| 연결 | connection.creation.rate, connection.creation.total | client가 broker 연결을 얼마나 자주 만들고 있는지 |
| 요청 지연 | node.request.latency.avg, node.request.latency.max | 특정 broker node와의 request latency |
| producer throttle | produce.throttle.time.avg, produce.throttle.time.max | quota나 broker 정책 때문에 produce가 지연되는 정도 |
| producer queue | record.queue.time.avg, record.queue.time.max | record batch가 send buffer에서 머문 시간 |
| consumer poll | poll.idle.ratio.avg | consumer가 poll loop에서 얼마나 idle하게 동작하는지 |
| consumer rebalance | rebalance.latency.max, rebalance 관련 count/rate | group coordination이 client 쪽에서 얼마나 흔들리는지 |
| fetch / commit | fetch latency, commit latency 계열 | consumer가 broker에서 데이터를 가져오고 offset을 기록하는 흐름 |
메트릭 이름은 OpenTelemetry 스타일의 telemetry metric name으로 표현됩니다. 예를 들어 Kafka producer의 request-latency-avg는 org.apache.kafka.producer.node.request.latency.avg 같은 형태로 변환됩니다.
여기서 중요한 운영 포인트는 “표준 메트릭”과 “Java client의 전체 내부 메트릭”을 구분하는 것입니다. Apache Kafka Java client는 reference implementation이므로 폭넓게 지원할 수 있지만, 다른 언어 클라이언트가 동일한 범위의 메트릭을 같은 속도로 지원한다고 가정하면 안 됩니다.
설정은 어떻게 하나
설정은 크게 두 단계입니다.
먼저 broker에 client telemetry를 받을 plugin을 구성해야 합니다. Apache Kafka는 broker-side plugin interface를 제공하지만, 실제로 어디로 export할지는 사용하는 배포판, plugin, 운영 환경에 따라 달라집니다. 예를 들어 OpenTelemetry Collector로 넘기거나, 별도 metrics backend로 전달하는 식입니다.
그 다음 client metrics subscription을 설정합니다. KIP-714은 CLIENT_METRICS config resource를 추가했고, Kafka 3.7.0 발표에 함께 언급된 KIP-1000은 이 resource를 kafka-configs.sh 같은 기존 도구로 관리할 수 있게 했습니다.
예시는 다음과 같은 형태입니다.
kafka-configs.sh --bootstrap-server "$BROKERS" \
--entity-type client-metrics \
--entity-name "java-producer-observability" \
--alter \
--add-config "metrics=[org.apache.kafka.producer.node.request.latency.,org.apache.kafka.producer.record.queue.time.],interval.ms=30000,match=[client_software_name=apache-kafka-java,client_id=orders-.*]"
이 설정은 개념적으로 이렇게 읽을 수 있습니다.
metrics: 수집할 telemetry metric prefixinterval.ms: 클라이언트가 메트릭을 push할 주기match: 어떤 클라이언트에 subscription을 적용할지 정하는 selector
match에는 client instance id, client id, client software name/version, source address/port 같은 기준을 사용할 수 있습니다. 다만 selector는 어디까지나 “지원 클라이언트가 자신을 보고할 때” 의미가 있습니다. 기능을 지원하지 않는 오래된 클라이언트는 이 필터링 대상에도 들어오지 않습니다.
이 기능이 유용한 순간
KIP-714이 의미 없는 기능이라는 뜻은 아닙니다. 오히려 조건이 맞으면 꽤 유용합니다.
특히 다음 상황에서는 좋은 보조 신호가 됩니다.
- 플랫폼 팀이 Kafka cluster를 관리하지만 애플리케이션 계측 표준은 팀마다 다른 경우
- Java 기반 Kafka client가 대부분이고, client library upgrade를 통제할 수 있는 경우
- 특정 client version, client.id, source address 범위의 문제를 broker 중심으로 좁히고 싶은 경우
- producer queue time, request latency, throttle time 같은 신호를 broker metric과 함께 보고 싶은 경우
- 신규 서비스에 대해 client-side observability baseline을 강제하고 싶은 경우
예를 들어 broker의 produce request latency가 높아졌을 때, 특정 client group에서만 record.queue.time.max가 같이 증가한다면 원인 범위를 좁히는 데 도움이 됩니다. consumer lag가 증가하는데 poll.idle.ratio.avg가 낮고 rebalance latency가 높다면 broker보다 consumer processing이나 group coordination 쪽을 먼저 볼 수 있습니다.
즉, 이 기능은 “문제를 자동으로 설명해주는 기능”이 아니라 “질문을 더 빨리 좁히게 해주는 표준화된 신호”에 가깝습니다.
왜 이것만으로는 부족한가
제가 이 기능을 조심스럽게 보는 이유는 기술 구조보다 도입 현실에 있습니다.
첫째, 모든 클라이언트를 지원 버전으로 올려야 합니다.
운영자가 보고 싶은 것은 “업그레이드가 잘 된 일부 서비스”가 아니라 “실제로 Kafka traffic을 만드는 모든 서비스”입니다. 하지만 조직 안에는 오래된 Java client, Spring Kafka wrapper, Kafka Streams app, Kafka Connect connector, Flink job, librdkafka 기반 서비스, Python/Go/Node client, vendor SDK, 배치성 유틸리티가 함께 존재합니다. 이들을 한 번에 지원 버전으로 올리는 일은 Kafka broker 업그레이드보다 더 오래 걸릴 수 있습니다.
둘째, Java가 아닌 클라이언트 생태계의 적용 속도는 운영자가 통제하기 어렵습니다.
KIP-714은 Java client를 기준 구현으로 삼습니다. 다른 클라이언트도 표준 메트릭을 지원할 수 있지만, 언제 어떤 범위까지 구현될지는 각 프로젝트와 vendor의 우선순위에 달려 있습니다. 운영 조직 입장에서는 가장 문제를 자주 만드는 클라이언트가 오히려 telemetry를 지원하지 않는 상황을 만날 수 있습니다.
셋째, 부분 관측은 때로 없는 관측보다 위험할 수 있습니다.
지원 클라이언트의 지표만 대시보드에 보이면 운영자는 “전체 Kafka client 상태”를 보고 있다고 느끼기 쉽습니다. 하지만 실제로는 telemetry를 보내는 subset만 보는 것입니다. 대시보드가 예뻐질수록 coverage gap은 더 잘 숨습니다.
넷째, broker도 추가 책임을 집니다.
Push interval rate limit, payload size, plugin export path, metrics backend 비용, broker restart 시 상태 유실, subscription 설계 같은 운영 포인트가 생깁니다. KIP 문서도 metrics request load가 감당하기 어려워지면 subscription을 줄이거나 제한하는 방향을 언급합니다. 클라이언트 메트릭은 공짜 신호가 아닙니다.
다섯째, 메트릭만으로 애플리케이션 원인을 설명할 수는 없습니다.
client telemetry는 Kafka client 내부 신호를 보여줄 수 있지만, 비즈니스 처리 시간, downstream API 지연, DB lock, application thread pool saturation, framework-level retry 같은 원인은 여전히 애플리케이션 계측과 로그가 필요합니다.
그래서 어떻게 써야 하나
실무적으로는 다음 정도의 위치가 적당합니다.
| 판단 | 권장 |
|---|---|
| 신규 Java 서비스 | 켜볼 가치가 큽니다. client.id 규칙과 버전 기준을 함께 정합니다. |
| 대부분 Java이고 upgrade 통제가 되는 조직 | platform baseline으로 검토할 수 있습니다. |
| 언어와 client library가 섞인 조직 | 전체 관측 전략이 아니라 부분 telemetry로 봐야 합니다. |
| ZooKeeper cluster | KRaft 전환 계획 없이는 우선순위를 낮게 둡니다. |
| 이미 app metrics가 잘 갖춰진 팀 | 중복 수집보다 broker 관점 correlation 가치가 있는지 봅니다. |
| 운영 대시보드 | coverage ratio를 반드시 같이 표시합니다. |
특히 coverage ratio는 중요합니다.
Kafka client telemetry dashboard =
metrics values
+ which clients are included
+ which clients are missing
이 세 번째 줄이 없으면 dashboard는 쉽게 과신을 만듭니다.
Konduo 관점에서 보면
Kafka를 이해할 때는 broker, topic, partition, consumer group을 코드 개념으로만 보지 않고 운영 신호로도 읽어야 합니다. Konduo는 Kafka 같은 클러스터형 리소스를 플러그인으로 연결해 상태, 메트릭 근거, 진단, 알림 대응을 하나의 운영 흐름에서 확인할 수 있도록 합니다. KIP-714 같은 client telemetry도 단독 정답이라기보다 broker 메트릭, consumer lag, 로그 근거, 애플리케이션 메트릭과 함께 해석할 때 더 실용적인 신호가 됩니다.
도입 전 체크리스트
KIP-714을 검토한다면 기능 자체보다 다음 질문을 먼저 확인하는 편이 좋습니다.
- Kafka cluster가 KRaft 기반인가?
- broker에 어떤 telemetry plugin을 배포하고, 어디로 export할 것인가?
- 전체 Kafka client 중 지원 버전으로 올라간 비율은 얼마인가?
- Java client와 non-Java client를 구분해 coverage를 볼 수 있는가?
- client.id 규칙이 운영자가 이해할 수 있을 만큼 일관적인가?
- subscription을 너무 넓게 잡아 broker와 metrics backend에 부담을 주지 않는가?
- dashboard에 “보이는 클라이언트”와 “보이지 않는 클라이언트”를 함께 표시하는가?
- 기존 app metric, JMX, broker metric, lag, log evidence와 어떤 관계로 볼 것인가?
마무리
KIP-714은 Kafka 운영에서 오래된 불편을 정면으로 다룹니다. 클라이언트 내부 상태를 애플리케이션 팀별 계측에만 맡기지 않고, Kafka protocol과 broker 구독 정책 안에서 표준화하려는 시도는 분명히 가치가 있습니다.
하지만 이 기능은 도입하면 바로 전체 client observability가 완성되는 기능이 아닙니다. 지원 클라이언트가 많을수록 가치가 커지고, 지원하지 않는 클라이언트가 많을수록 빈틈도 커집니다. 특히 오래된 client와 여러 언어 client가 섞인 조직에서는 그 빈틈이 작지 않습니다.
따라서 이 기능을 “새로운 기본 관측 계층”으로 기대하기보다, “지원되는 클라이언트에서 추가로 얻을 수 있는 broker-mediated telemetry”로 보는 편이 안전합니다.
좋은 운영 판단은 더 많은 숫자를 모으는 데서 끝나지 않습니다. 어떤 숫자가 보이고, 어떤 숫자가 아직 보이지 않는지 함께 아는 데서 시작합니다.
함께 읽기 좋은 글
이 글의 관점과 이어지는 주제를 더 보려면 아래 글도 함께 읽어볼 수 있습니다.
- JVM 메트릭만으로는 컨테이너를 설명할 수 없다 - JVM 밖의 cgroup, filesystem, fd, I/O 신호를 함께 봐야 하는 이유를 다룹니다.
- 겉보기엔 균형 잡힌 Kafka, Broker Metrics는 다르게 말한다 - leader 수보다 실제 broker 부하를 봐야 하는 이유를 다룹니다.
- Consumer Lag은 건강 점수가 아니다: Kafka Consuming Pressure라는 관점 - consumer lag을 처리 압력 관점으로 다시 해석합니다.