Kafka 관측 가능성 모범 사례¶
개요¶
Kafka는 LinkedIn에서 개발한 분산형 게시-구독 모델 기반의 메시지 큐로, 실시간 데이터 처리 시스템이며 수평 확장이 가능합니다. RabbitMQ, RocketMQ 등 미들웨어와 마찬가지로 몇 가지 주요 특징을 가지고 있습니다:
- 비동기 처리
- 서비스 결합 분리
- 트래픽 피크 분산
아래는 비동기 처리의 예시 다이어그램입니다.
아키텍처¶
아래 그림과 같이, Kafka 아키텍처는 여러 개의 Producer, 여러 개의 Consumer, 여러 개의 Broker 및 하나의 Zookeeper 클러스터로 구성됩니다.
- Zookeeper: Kafka 클러스터는 Zookeeper를 통해 클러스터 구성을 관리합니다. Leader를 선출하고, Consumer Group에 변경이 발생하면 Rebalance를 수행합니다.
- Broker: 메시지 미들웨어 처리 노드입니다. 하나의 노드는 하나의 Broker이며, 하나의 Kafka 클러스터는 하나 이상의 Broker로 구성됩니다. 하나의 메시지는 여러 Broker에 분산될 수 있습니다.
- Producer: 생산자로, Broker에 메시지를 게시하는 역할을 담당합니다.
- Consumer: 소비자로, Broker에서 메시지를 읽어옵니다.
- Consumer Group: 각 Consumer는 특정 Consumer Group에 속하며, 이 Group에 이름을 지정할 수 있습니다. 지정하지 않으면 기본 Group에 속합니다. 하나의 메시지는 여러 Group으로 전송될 수 있지만, 하나의 Group 내에서는 하나의 Consumer만이 해당 메시지를 소비할 수 있습니다.
Kafka는 메시지를 분류하며, 클러스터로 전송되는 모든 메시지는 Topic을 지정해야 합니다. 하나의 Topic은 하나의 메시지 유형이며, 논리적으로 하나의 Queue로 간주됩니다. Producer가 생산하는 각 메시지는 반드시 하나의 Topic을 지정해야 하며, Consumer는 구독한 Topic에 따라 해당 Broker로부터 메시지를 가져옵니다. 각 Topic은 하나 이상의 Partition을 포함하며, 하나의 Partition은 하나의 폴더에 해당합니다. 이 폴더 아래에는 Partition의 데이터와 인덱스 파일이 저장되며, 각 Partition 내부는 순서가 정렬되어 있습니다. 이렇게 하나의 Topic은 하나 이상의 Partition으로 나뉘고, 각 Partition은 여러 개의 복제본을 가지며 이들은 서로 다른 Broker에 분산됩니다. 하나의 파티션에 있는 여러 복제본은 하나의 Leader(주)와 여러 개의 Follower(종) 관계를 가지며, Leader는 외부 서비스를 제공합니다. 여기서 외부란 클라이언트 프로그램과의 상호작용을 의미하며, Follower는 Leader를 수동적으로 동기화할 뿐 외부와 상호작용할 수 없습니다. 다중 복제본 메커니즘을 통해 장애 자동 전환이 구현되어, 클러스터 내 특정 Broker에 장애가 발생하더라도 서비스 가용성을 보장할 수 있어 재해 복구 능력을 향상시킵니다. 아래 그림과 같이, Kafka 클러스터에는 4개의 Broker가 있으며, 특정 Topic은 3개의 파티션을 가지고 있습니다. 복제본 팩터도 3으로 설정되었다고 가정하면, 각 파티션은 하나의 Leader와 두 개의 Follower 복제본을 갖게 됩니다.
파티션 복제본은 서로 다른 Broker에 위치하며, 생산자와 소비자는 Leader 복제본과만 상호작용하고, Follower 복제본은 메시지 동기화만 담당합니다. Leader 복제본에 장애가 발생하면, Follower 복제본 중에서 새로운 Leader 복제본이 선출되어 외부 서비스를 제공합니다.
이제 Kafka 다중 복제본 메커니즘의 몇 가지 중요한 용어를 살펴보겠습니다.
- AR(Assigned Replicas): 하나의 파티션에 있는 모든 복제본을 통칭하여 AR이라고 합니다.
- ISR(In-Sync Replicas): Leader 복제본과 일정 수준의 동기화를 유지하는 모든 Follower 복제본(Leader 자체 포함)으로 ISR이 구성됩니다.
- OSR(Out-of-Sync Replicas): ISR과 반대로, Leader 복제본과 일정 수준의 동기화를 유지하지 못하는 모든 Follower 복제본으로 OSR이 구성됩니다.
먼저, 생산자는 Leader 복제본에 메시지를 전송한 후, Follower 복제본이 Leader로부터 메시지를 가져와 동기화할 수 있습니다. 동일한 시점에 모든 복제본의 메시지는 완전히 동일하지 않습니다. 즉, 동기화 기간 동안 Follower는 Leader에 비해 어느 정도 지연이 발생합니다. 이에 따라 세 가지 관계를 확인할 수 있습니다: AR = ISR + OSR.
Leader는 ISR 집합에 있는 모든 Follower 복제본의 지연 상태를 유지 관리하고 추적하는 역할을 담당합니다. Follower가 너무 많이 지연되거나 장애가 발생하면 Leader는 해당 Follower를 ISR 집합에서 제외합니다. 물론, OSR 집합에 있는 Follower의 동기화 범위가 Leader를 따라잡으면, Leader는 해당 Follower를 OSR 집합에서 ISR 집합으로 이동시킵니다. 일반적으로 Leader에 장애가 발생하거나失效할 경우, ISR 집합에 있는 Follower만이 새로운 Leader로 선출될 자격이 있으며, OSR 집합에 있는 Follower는 이러한 기회가 없습니다(단, 매개변수 구성을 변경하여 변경할 수 있습니다).
Kafka 모니터링을 위한 핵심 지표¶
다음으로 Kafka 지표에 대한 자세한 정보를 소개합니다.
UnderReplicatedPartitions¶
UnderReplicatedPartitions는 동기화되지 않은 상태의 파티션 개수, 즉 장애 복제본의 파티션 수를 나타냅니다. 이상 값은 0이 아닙니다. 정상적으로 작동하는 클러스터에서 동기화 복제본(ISR)의 수는 전체 복제본 수와 정확히 일치해야 합니다. 이 값이 0이 아니면 Broker의 Leader 파티션에 완전히 동기화되지 않았거나 ISR을 따라잡지 못한 복제본이 있는 파티션 수가 있음을 의미합니다. 발생 가능한 문제:
- 특정 Broker 다운.
- 복제본이 있는 디스크 장애/쓰기 가득 참으로 인해 복제본이 오프라인 상태가 됨. OfflineLogDirectoryCount 지표가 0이 아닌 값과 결합하여 판단할 수 있음.
- 성능 문제로 인해 복제본이 동기화를 따라가지 못함. 두 가지 경우가 있을 수 있습니다. 첫째, Follower 복제본 프로세스가 중단되어 일정 시간 동안 Leader에 동기화 요청을 전혀 보내지 않는 경우(예: 잦은 Full GC). 둘째, Follower 복제본 프로세스의 동기화 속도가 느려 일정 시간 내에 Leader 복제본을 따라잡지 못하는 경우(예: I/O 오버헤드 과다).
| 지표 집합 | kafka_replica_manager | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| UnderReplicatedPartitions | 동기화되지 않은 상태의 Partition 개수 | int |
| UnderMinIsrPartitionCount | 최소 ISR 미만인 Partition 개수. | int |
OfflineLogDirectoryCount¶
OfflineLogDirectoryCount는 오프라인 로그 디렉터리 수입니다. 이상 값은 0이 아닙니다. 오프라인 로그 디렉터리가 있는지 확인하려면 이 지표를 모니터링해야 합니다.
| 지표 집합 | kafka_log | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| OfflineLogDirectoryCount | 오프라인 로그 디렉터리 수 | int |
IsrShrinksPerSec / IsrExpandsPerSec¶
임의 파티션의 동기화 상태에 있는 복제본 수(ISR)는 Broker 노드를 확장하거나 파티션을 삭제하지 않는 한 안정적으로 유지되어야 합니다. 고가용성을 유지하기 위해 Kafka 클러스터는 특정 파티션의 Leader가 다운될 때 Follower가 이를 인수할 수 있도록 최소 ISR 수를 보장해야 합니다. 복제본이 ISR 풀에서 제거되는 몇 가지 이유는 다음과 같습니다: Follower의 오프셋이 Leader보다 훨씬 뒤쳐진 경우(replica.lag.max.messages 구성 항목 변경), 또는 특정 Follower가 일정 시간 동안 Leader와 연결이 끊어진 경우(replica.socket.timeout.ms 구성 항목 변경). 이유가 무엇이든 IsrShrinksPerSec(ISR 축소)이 증가했지만 그에 따른 IsrExpandsPerSec(ISR 확장)의 증가가 없다면 주의를 기울이고 수동 개입이 필요합니다.
| 지표 집합 | kafka_replica_manager | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| IsrShrinksPerSec.Count | ISR 축소 수 | int |
| IsrShrinksPerSec.OneMinuteRate | ISR 축소 빈도 | float |
| IsrExpandsPerSec.Count | ISR 확장 수 | int |
| IsrExpandsPerSec.OneMinuteRate | ISR 확장 빈도 | float |
ActiveControllerCount¶
ActiveControllerCount는 현재 활성화된 컨트롤러의 수입니다. 이상 값은 0입니다. Kafka 클러스터에서 첫 번째로 시작된 노드는 자동으로 Controller가 되며, 이러한 노드는 하나만 존재할 수 있습니다. 정상적인 경우 Controller가 있는 Broker의 이 지표는 1이어야 하며, 다른 Broker의 이 값은 0이어야 합니다. Controller의 역할은 파티션 Leader 목록을 유지 관리하고 특정 Leader를 사용할 수 없을 때 Leader 변경을 조정하는 것입니다. Controller를 교체해야 하는 경우, Zookeeper가 Broker 풀에서 무작위로 새로운 Controller를 선택합니다. 일반적으로 이 값이 1보다 클 수는 없지만, 이 값이 0이고 일정 시간(<1) 동안 지속될 경우 명확한 경고를 발행해야 하므로 이 지표는 알림에 사용할 수 있습니다.
| 지표 집합 | kafka_controller | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| ActiveControllerCount.Value | Controller 활성 수 | int |
OfflinePartitionsCount¶
OfflinePartitionsCount는 활성 Leader가 없는 파티션 수입니다. 이상 값은 0이 아닙니다. 모든 읽기 및 쓰기 작업은 Partition Leader에서만 수행되므로, 활성 Leader가 없는 파티션은 완전히 사용할 수 없게 되며 해당 파티션의 소비자와 생산자는 Leader를 사용할 수 있을 때까지 모두 차단됩니다. 이 지표는 알림에 사용할 수 있습니다.
| 지표 집합 | kafka_controller | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| OfflinePartitionsCount.Value | 오프라인 Partition 수 | int |
LeaderElectionRateAndTimeMs¶
Partition Leader가 다운되면 선거가 트리거되어 새 Leader 선거가 시작됩니다. LeaderElectionRateAndTimeMs를 통해 Leader가 초당 몇 번 선거를 수행하는지, 선거 빈도를 관찰할 수 있습니다.
| 지표 집합 | kafka_controller | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| LeaderElectionRateAndTimeMs.Count | Leader 선거 횟수 | int |
| LeaderElectionRateAndTimeMs.OneMinuteRate | Leader 선거 비율 | float |
| LeaderElectionRateAndTimeMs.50thPercentile | Leader 선거 비율 | float |
| LeaderElectionRateAndTimeMs.75thPercentile | Leader 선거 비율 | float |
| LeaderElectionRateAndTimeMs.99thPercentile | Leader 선거 비율 | float |
UncleanLeaderElectionsPerSec¶
Kafka Broker 파티션 Leader를 사용할 수 없게 되면 unclean Leader 선거가 발생하며, 해당 파티션의 ISR 집합에서 새 Leader가 선출됩니다. 본질적으로, unclean leader 선거는 가용성을 위해 일관성을 희생합니다. 동기화에 사용 가능한 복제본이 없어 동기화되지 않은 복제본 중에서 Leader 선거를 진행해야 하는 경우, 이전 Leader의 동기화되지 않은 메시지는 모두 영원히 손실됩니다. UncleanLeaderElectionsPerSec.Count의 이상 값은 0이 아니며, 이는 데이터 손실을 의미하므로 알림이 필요합니다.
| 지표 집합 | kafka_controller | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| UncleanLeaderElectionsPerSec.Count | Unclean Leader 선거 횟수 | int |
TotalTimeMs¶
TotalTimeMs 측정값은 네 가지 지표의 합계입니다:
- queue: 요청 큐에서 대기하는 데 소요된 시간
- local: 리더가 처리하는 데 소요된 시간
- remote: 팔로워 응답을 기다리는 데 소요된 시간(requests.required.acks=-1인 경우에만 해당)
- response: 응답을 보내는 시간
TotalTimeMs는 서버 요청 처리 시간을 측정하는 데 사용됩니다. 정상적인 경우 이 지표는 비교적 안정적이며 매우 작은 변동만 있습니다. 이상이 발견되면 불규칙한 데이터 변동이 나타납니다. 이때 queue, local, remote 및 response 값을 각각 확인하여 지연의 원인이 어느 세그먼트에 있는지 찾아야 합니다.
| 지표 집합 | kafka_request | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| TotalTimeMs.Count | 총 요청 처리 시간 | int |
PurgatorySize¶
PurgatorySize: 생산(produce) 및 소비(fetch) 요청이 필요할 때까지 대기하는 임시 저장 영역입니다. Purgatory의 크기를 주시하면 잠재 지연의 근본 원인을 파악하는 데 도움이 됩니다. 예를 들어, Purgatory 큐에서 가져오기 요청의 수가 상응하여 증가하면 소비자 가져오기 시간의 증가를 쉽게 설명할 수 있습니다.
| 지표 집합 | kafka_purgatory | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| Fetch.PurgatorySize | Fetch Purgatory 크기 | int |
| Produce.PurgatorySize | Produce Purgatory 크기 | int |
| Rebalance.PurgatorySize | Rebalance Purgatory 크기 | int |
| topic.PurgatorySize | topic Purgatory 크기 | int |
| ElectLeader.PurgatorySize | Leader 선거 Purgatory 크기 | int |
| DeleteRecords.PurgatorySize | 레코드 삭제 Purgatory 크기 | int |
| DeleteRecords.NumDelayedOperations | 지연된 레코드 삭제 수 | int |
| Heartbeat.NumDelayedOperations | 하트비트 모니터링 | int |
BytesInPerSec / BytesOutPerSec¶
BytesInPerSec/BytesOutPerSec는 수신/송신 바이트 수입니다. 일반적으로 디스크 처리량, 네트워크 처리량이 병목 현상이 될 수 있습니다. 데이터 센터 간에 메시지를 전송하거나, Topic 수가 많거나, 복제본이 Leader를 따라잡고 있는 경우 네트워크 처리량이 Kafka 성능에 영향을 미칠 수 있습니다. 이러한 지표를 통해 Broker의 네트워크 처리량을 추적하여 병목 현상이 발생하는 위치를 파악할 수 있습니다.
| 지표 집합 | kafka_topics | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| BytesInPerSec.Count | 초당 유입 바이트 수 | int |
| BytesInPerSec.OneMinuteRate | 초당 유입 속도 | float |
| BytesOutPerSec.Count | 초당 유출 바이트 수 | int |
| BytesOutPerSec.OneMinuteRate | 초당 유출 속도 | float |
RequestsPerSec¶
RequestsPerSec는 초당 요청 횟수입니다. 이 지표를 모니터링하면 생산자와 소비자의 요청률을 실시간으로 파악하여 Kafka가 효율적으로 통신하도록 할 수 있습니다. 이 지표가 지속적으로 높은 수준을 유지하면 생산자 또는 소비자 수를 늘려 처리량을 높이고 불필요한 네트워크 오버헤드를 줄이는 것을 고려할 수 있습니다.
| 지표 집합 | kafka_topics | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| TotalFetchRequestsPerSec.Count | 초당 가져오기 요청 횟수 | int |
| TotalProduceRequestsPerSec.Count | 생산자 초당 쓰기 요청 횟수 | int |
| FailedFetchRequestsPerSec.Count | Topic 실패 Fetch 수 | int |
| FailedProduceRequestsPerSec.Count | 전송 요청 실패 속도 | int |
기타 일반 지표¶
| 지표 집합 | kafka_controller | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| GlobalTopicCount.Value | 클러스터 전체 Topic 수 | int |
| GlobalPartitionCount.Value | 파티션 수 | int |
| TotalQueueSize.Value | 큐 총 개수 | int |
| EventQueueSize.Value | 이벤트 큐 수 | int |
| 지표 집합 | kafka_request | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| RequestQueueTimeMs.Count | 요청 큐 시간 | int |
| ResponseSendTimeMs.Count | 응답 큐 시간 | int |
| MessageConversionsTimeMs.Count | 메시지 변환 시간 | int |
| 지표 집합 | kafka_topics | |
|---|---|---|
| 지표 | 설명 | 데이터 유형 |
| PartitionCount.Value | Partition 수 | int |
| LeaderCount.Value | Leader 수 | int |
| BytesRejectedPerSec.Count | Topic 요청 거부 수 | int |
시나리오 뷰¶
Guance을 사용하여 Kafka를 관측하기 전에 먼저 Guance 계정을 등록해야 합니다. 등록이 완료되면 Guance 워크스페이스에 로그인합니다. 그런 다음 <Kafka 통합 문서>에 따라 Kafka의 관측 가능성을 구현하십시오.



