브로커 부하 분산기 개발

브로커 부하 분산기 개발 (Broker Load Balancer)

브로커 부하 분산기를 직접 개발하려면 Pulsar가 제공하는 부하 관리자(load manager) 유형과 그 개념을 이해해야 해요. Pulsar에는 단순형(Simple), 모듈형(Modular), 확장형(Extensible) 부하 관리자가 있으며, 각각 다른 방식으로 번들(bundle)을 브로커에 배분해요. 이 글에서는 부하 관리자의 개념과 활성화·검증 방법을 정리해 드릴게요.

출처: 문서

본문

브로커 부하 분산기를 개발하고 싶다면 다음 문서를 확인해 보세요.

Pulsar에는 다음과 같은 유형의 부하 관리자가 있어요:

  • 단순 부하 관리자(Simple load manager): SimpleLoadManagerImpl에 구현되어 있으며, 부하가 관리되는 방식을 단순화하면서도 복잡한 부하 관리 전략을 구현할 수 있게 추상화를 제공해요.
  • 모듈형 부하 관리자(Modular load manager): ModularLoadManagerImpl에 구현되어 있으며, SimpleLoadManagerImpl의 유연한 대안이에요.
  • 확장형 부하 관리자(Extensible load manager): ExtensibleLoadManagerImpl에 구현되어 있으며, 부하 분산 메타데이터 저장과 복제를 위해 시스템 토픽과 테이블 뷰에 의존해요.

개념

구현을 시작하기 전에 다음 기본 사항을 이해하세요.

참고 다음 개념은 모듈형 부하 관리자에만 사용할 수 있어요.

데이터

모듈형 부하 관리자가 모니터링하는 데이터는 LoadData 클래스에 포함돼 있어요. 여기서 사용 가능한 데이터는 번들 데이터와 브로커 데이터로 세분화돼요.

브로커

브로커 데이터는 BrokerData 클래스에 포함돼 있어요. 두 부분으로 더 세분화되는데, 하나는 각 브로커가 개별적으로 ZooKeeper에 쓰는 로컬 데이터이고, 다른 하나는 리더 브로커가 ZooKeeper에 쓰는 이력 브로커 데이터예요.

리드 브로커

모듈형 부하 관리자는 중앙 집중식이에요. 즉 번들을 할당하는 모든 요청(이전에 보았든 처음이든)이 리드 브로커(시간에 따라 바뀔 수 있음)에서만 처리돼요. 현재 리드 브로커를 확인하려면 ZooKeeper의 /loadbalance/leader 노드를 살펴보세요.

로컬 브로커 데이터

로컬 브로커 데이터는 LocalBrokerData 클래스에 포함돼 있으며 다음 리소스에 대한 정보를 제공해요:

  • CPU 사용량
  • JVM 힙 메모리 사용량
  • 다이렉트 메모리 사용량
  • 대역폭 in/out 사용량
  • 모든 번들에 걸친 가장 최근 총 메시지 비율 in/out
  • 총 토픽, 번들, 프로듀서, 소비자 수
  • 이 브로커에 할당된 모든 번들의 이름
  • 이 브로커에 대한 번들 할당의 가장 최근 변경 사항

로컬 브로커 데이터는 서비스 구성 loadBalancerReportUpdateMaxIntervalMinutes에 따라 주기적으로 갱신돼요. 브로커가 로컬 브로커 데이터를 갱신한 후에는 리더 브로커가 ZooKeeper watch를 통해 갱신 내용을 즉시 받아요. 로컬 데이터는 ZooKeeper 노드 /loadbalance/brokers/<broker host/port>에서 읽혀요.

이력 브로커 데이터

이력 브로커 데이터는 TimeAverageBrokerData 클래스에 포함돼 있어요.

안정 상태 시나리오에서 좋은 결정을 내리고 위기 시나리오에서 반응적인 결정을 내려야 하는 필요를 조정하기 위해, 이력 데이터는 두 부분으로 나뉘어요. 반응적 결정을 위한 단기 데이터와 안정 상태 결정을 위한 장기 데이터예요. 두 시간 프레임 모두 다음 정보를 유지해요:

  • 브로커 전체의 메시지 비율 in/out
  • 브로커 전체의 메시지 처리량 in/out

브로커 데이터는 번들 데이터와 달리 전역 브로커 메시지 비율과 처리량에 대한 샘플을 유지하지 않아요. 새 번들이 제거되거나 추가되면서 안정적으로 유지될 것으로 기대되지 않기 때문이에요. 대신 이 데이터는 번들에 대한 단기·장기 데이터에 걸쳐 집계돼요. 이 데이터가 어떻게 수집·유지되는지 이해하려면 번들 데이터 섹션을 보세요.

이력 브로커 데이터는 브로커가 로컬 데이터를 ZooKeeper에 쓸 때마다 리더 브로커가 각 브로커에 대해 메모리에서 갱신해요. 그런 다음 이력 데이터는 리더 브로커가 구성 loadBalancerResourceQuotaUpdateIntervalMinutes에 따라 주기적으로 ZooKeeper에 써요.

번들 데이터

번들 데이터는 BundleData에 포함돼 있어요. 이력 브로커 데이터처럼 번들 데이터도 단기·장기 시간 프레임으로 나뉘어요. 각 시간 프레임에서 유지되는 정보:

  • 이 번들의 메시지 비율 in/out
  • 이 번들의 메시지 처리량 in/out
  • 이 번들의 현재 샘플 수

시간 프레임은 이러한 값들의 평균을 제한된 수의 샘플 집합에 걸쳐 유지함으로써 구현돼요. 샘플은 로컬 데이터의 메시지 비율과 처리량 값에서 얻어요. 따라서 로컬 데이터의 갱신 간격이 2분이라면, 단기 샘플 수가 10이고 장기 샘플 수가 1000이라면, 단기 데이터는 10 samples * 2 minutes / sample = 20 minutes 기간에 걸쳐 유지되고, 장기 데이터도 마찬가지로 2000분 기간에 걸쳐 유지돼요. 주어진 시간 프레임을 충족할 샘플이 충분하지 않을 때마다 평균은 기존 샘플에 대해서만 계산돼요. 샘플이 없으면 첫 번째 샘플로 덮어쓸 때까지 기본값이 가정돼요. 현재 기본값은 다음과 같아요:

  • 메시지 비율 in/out: 양방향 초당 50개 메시지
  • 메시지 처리량 in/out: 양방향 초당 50KB

번들 데이터는 브로커가 로컬 데이터를 ZooKeeper에 쓸 때마다 리더 브로커에서 메모리로 갱신돼요. 그런 다음 번들 데이터는 이력 브로커 데이터와 같은 시점에 리더 브로커가 구성 loadBalancerResourceQuotaUpdateIntervalMinutes에 따라 주기적으로 ZooKeeper에 써요.

트래픽 분산

모듈형 부하 관리자는 ModularLoadManagerStrategy가 제공하는 추상화를 사용해 번들 할당에 대한 결정을 내려요. 이 전략은 서비스 구성, 전체 부하 데이터, 할당할 번들의 번들 데이터를 고려해 결정을 내려요. 현재 지원되는 유일한 전략은 LeastLongTermMessageRate이며, 곧 사용자가 원하면 자신의 전략을 주입할 수 있게 될 거예요.

최소 장기 메시지 비율 전략

이름에서 알 수 있듯이, 최소 장기 메시지 비율(least long-term message rate) 전략은 각 브로커의 장기 시간 창의 메시지 비율이 대략 같아지도록 번들을 브로커에 분산하려 해요. 하지만 메시지 비율만으로 부하를 균형 맞추면 각 브로커에서 메시지별 비대칭 리소스 부담 문제를 처리하지 못해요. 따라서 CPU, 메모리, 다이렉트 메모리, 대역폭 in, 대역폭 out이라는 시스템 리소스 사용량도 할당 과정에서 고려돼요. 이는 최종 메시지 비율을 1 / (overload_threshold - max_usage)로 가중치를 두어 이루어져요. 여기서 overload_threshold는 구성 loadBalancerBrokerOverloadedThresholdPercentage에 해당하고, max_usage는 후보 브로커가 사용 중인 시스템 리소스 중 최대 비율이에요. 이 승수는 같은 메시지 비율에 더 많이 부담을 받는 머신이 더 적은 부하를 받도록 보장해요. 특히 한 머신이 과부하되면 모든 머신이 대략 과부하되도록 보장하려 해요. 브로커의 최대 사용량이 과부하 임계값을 초과하는 경우 그 브로커는 번들 할당에서 고려되지 않아요. 모든 브로커가 과부하되면 번들은 무작위로 할당돼요.

활성화

아래 단계에 따라 단순형, 모듈형 또는 확장형 부하 관리자를 활성화할 수 있어요.

참고 단순형·모듈형 부하 관리자에 대해:

  • 부하 관리자 지정에 실수가 있으면 Pulsar가 SimpleLoadManagerImpl로 기본 설정돼요.
  • 부하 관리자를 지정하지 않으면 기본 부하 관리자(ModularLoadManagerImpl)가 사용돼요.

단순 부하 관리자 활성화

다음 방법 중 하나로 단순 부하 관리자를 활성화할 수 있어요:

  • 방법 1: conf/broker.conf에서 loadManagerClassName 값을 org.apache.pulsar.broker.loadbalance.impl.SimpleLoadManagerImpl로 갱신해요.

  • 방법 2: pulsar-admin 도구 사용.

    pulsar-admin brokers update-dynamic-config \
    --config loadManagerClassName \
    --value org.apache.pulsar.broker.loadbalance.impl.SimpleLoadManagerImpl
    

모듈형 부하 관리자 활성화

다음 방법 중 하나로 모듈형 부하 관리자를 활성화할 수 있어요:

  • 방법 1: conf/broker.conf에서 loadManagerClassName 값을 org.apache.pulsar.broker.loadbalance.impl.ModularLoadManagerImpl로 갱신해요.

  • 방법 2: pulsar-admin 도구 사용.

    pulsar-admin brokers update-dynamic-config \
    --config loadManagerClassName \
    --value org.apache.pulsar.broker.loadbalance.impl.ModularLoadManagerImpl
    

확장형 부하 관리자 활성화

conf/broker.conf에서 loadManagerClassName 값을 org.apache.pulsar.broker.loadbalance.extensions.ExtensibleLoadManagerImpl로 갱신해 확장형 부하 관리자를 활성화할 수 있어요.

참고 확장형 부하 관리자 활성화는 pulsar-admin 도구를 지원하지 않아요.

검증

어떤 부하 관리자가 사용되는지 확인하고 싶다면 아래 단계를 따르세요.

1단계: loadManagerClassName 확인

pulsar-admin 도구로 loadManagerClassName 요소를 검사할 수 있어요.

입력

bin/pulsar-admin brokers get-all-dynamic-config

출력

{
"loadManagerClassName" : "org.apache.pulsar.broker.loadbalance.impl.ModularLoadManagerImpl"
}

loadManagerClassName 요소가 없으면 conf/broker.conf 파일의 loadManagerClassName 값이 사용돼요.

2단계: 부하 관리자 확인 (선택)

어떤 부하 관리자가 사용되는지 다시 확인하려면 ZooKeeper 부하 보고서를 확인하거나 monitor-brokers 출력을 확인할 수 있어요.

방법 1: 부하 보고서 확인

부하 관리자마다 부하 보고서가 달라요. 출력을 기준으로 어떤 부하 관리자가 사용되는지 확인할 수 있어요.

  • 단순형
  • 모듈형
  • 확장형

ZooKeeper 부하 보고서를 확인할 수 있어요.

  1. ZooKeeper에 연결해요. 입력 bin/pulsar zookeeper-shell -server zookeeper:2181
  2. 모든 브로커를 나열해요. 입력 ls /loadbalance/brokers 출력 이 출력은 브로커가 2개 있다는 것을 보여줘요. [broker-1:8080, broker-2:8080]
  3. 브로커 1의 ZooKeeper 부하 보고서를 확인해요. 부하 보고서는 /loadbalance/brokers/...에 있어요. 입력 get /loadbalance/brokers/broker-1:8080

단순형 부하 관리자의 부하 보고서에는 "loadReportType":"LoadReport"가 포함돼요:

{"name":"broker-1:8080","brokerVersionString":"3.1.0-SNAPSHOT","webServiceUrl":"http://broker-1:8080","pulsarServiceUrl":"pulsar://broker-1:6650","persistentTopicsEnabled":true,"nonPersistentTopicsEnabled":true,"timestamp":1691042931108,"msgRateIn":0.0,"msgRateOut":0.0,"numTopics":0,"numConsumers":0,"numProducers":0,"numBundles":0,"protocols":{},"loadManagerClassName":"org.apache.pulsar.broker.loadbalance.impl.SimpleLoadManagerImpl","startTimestamp":1691042931108,"systemResourceUsage":{"bandwidthIn":{"usage":0.595387281695773,"limit":1.0E7},"bandwidthOut":{"usage":0.5799226769764033,"limit":1.0E7},"cpu":{"usage":6.224803359552059,"limit":800.0},"memory":{"usage":152.0,"limit":2096.0},"directMemory":{"usage":0.0,"limit":256.0}},"bundleStats":{},"bundleGains":[],"bundleLosses":[],"allocatedCPU":0.0,"allocatedMemory":0.0,"allocatedBandwidthIn":0.0,"allocatedBandwidthOut":0.0,"allocatedMsgRateIn":0.0,"allocatedMsgRateOut":0.0,"preAllocatedCPU":0.0,"preAllocatedMemory":0.0,"preAllocatedBandwidthIn":0.0,"preAllocatedBandwidthOut":0.0,"preAllocatedMsgRateIn":0.0,"preAllocatedMsgRateOut":0.0,"underLoaded":true,"overLoaded":false,"loadReportType":"LoadReport","msgThroughputIn":0.0,"msgThroughputOut":0.0,"bandwidthIn":{"usage":0.595387281695773,"limit":1.0E7},"bandwidthOut":{"usage":0.5799226769764033,"limit":1.0E7},"memory":{"usage":152.0,"limit":2096.0},"cpu":{"usage":6.224803359552059,"limit":800.0},"directMemory":{"usage":0.0,"limit":256.0},"lastUpdate":1691042931108}

모듈형 부하 관리자의 부하 보고서에는 "loadReportType":"LocalBrokerData"와 번들 목록이 포함돼요:

{"webServiceUrl":"http://broker-1:8080","pulsarServiceUrl":"pulsar://broker-1:6650","persistentTopicsEnabled":true,"nonPersistentTopicsEnabled":true,"cpu":{"usage":7.311714728372232,"limit":800.0},"memory":{"usage":124.0,"limit":2096.0},"directMemory":{"usage":36.0,"limit":256.0},"bandwidthIn":{"usage":0.8324254085661579,"limit":1.0E7},"bandwidthOut":{"usage":0.7155446715644209,"limit":1.0E7},"msgThroughputIn":0.0,"msgThroughputOut":0.0,"msgRateIn":0.0,"msgRateOut":0.0,"lastUpdate":1690979816792,"lastStats":{"my-tenant/my-namespace/0x4ccccccb_0x66666664":{"msgRateIn":0.0,"msgThroughputIn":0.0,"msgRateOut":0.0,"msgThroughputOut":0.0,"consumerCount":2,"producerCount":0,"topics":1,"cacheSize":0}},"numTopics":1,"numBundles":1,"numConsumers":2,"numProducers":0,"bundles":["my-tenant/my-namespace/0x4ccccccb_0x66666664"],"lastBundleGains":[],"lastBundleLosses":[],"brokerVersionString":"3.1.0-SNAPSHOT","protocols":{},"advertisedListeners":{"internal":{"brokerServiceUrl":"pulsar://broker-1:6650"}},"loadManagerClassName":"org.apache.pulsar.broker.loadbalance.impl.ModularLoadManagerImpl","startTimestamp":1690940955211,"maxResourceUsage":0.140625,"loadReportType":"LocalBrokerData"}

참고 확장형 부하 관리자는 내부 stats가 ZooKeeper가 아닌 시스템 토픽에 저장되므로 ZooKeeper 부하 보고서가 없어요.

pulsar-client 도구를 사용해 시스템 토픽에서 부하 보고서를 확인할 수 있어요.

입력

bin/pulsar-client consume non-persistent://pulsar/system/loadbalancer-broker-load-data --subscription-name test

출력 (로그 중 일부와 메시지 내용)

----- got message -----
key:[broker-1:8080], properties:[], content:{"cpu":{"usage":14.397985201479854,"limit":800.0},"memory":{"usage":300.0,"limit":2096.0},"directMemory":{"usage":40.0,"limit":256.0},"bandwidthIn":{"usage":0.7817884878178855,"limit":1.0E7},"bandwidthOut":{"usage":0.7213945272139455,"limit":1.0E7},"msgThroughputIn":3.000538680274058,"msgThroughputOut":3.0005621893825616,"msgRateIn":0.03333931866971176,"msgRateOut":0.033339579882028465,"bundleCount":3,"topics":3,"maxResourceUsage":0.15625,"weightedMaxEMA":0.15625,"msgThroughputEMA":38.88925615962549,"updatedAt":1691043751060,"reportedAt":1691043631073}

방법 2: monitor-brokers 출력 확인

pulsar-perf 도구를 사용해 브로커 모니터를 시작할 수 있어요.

부하 관리자마다 출력이 달라요. 이 출력은 방법 1: ZooKeeper 부하 보고서 확인의 출력과 동일하지만 가독성을 위해 잘 정렬되어 있어요.

입력

pulsar-perf monitor-brokers --connect-string <zookeeper host:port>

출력 (단순형 부하 관리자 예시)

===================================================================================================================
|||COUNT          |TOPIC          |BUNDLE         |PRODUCER       |CONSUMER       |BUNDLE +       |BUNDLE -       ||
|||               |4              |4              |0              |2              |0              |0              ||
|||RAW SYSTEM     |CPU %          |MEMORY %       |DIRECT %       |BW IN %        |BW OUT %       |MAX %          ||
|||               |0.25           |47.94          |0.01           |0.00           |0.00           |47.94          ||
|||ALLOC SYSTEM   |CPU %          |MEMORY %       |DIRECT %       |BW IN %        |BW OUT %       |MAX %          ||
|||               |0.20           |1.89           |               |1.27           |3.21           |3.21           ||
|||RAW MSG        |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |0.00           |0.00           |0.00           |0.01           |0.01           |0.01           ||
|||ALLOC MSG      |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |54.84          |134.48         |189.31         |126.54         |320.96         |447.50         ||
===================================================================================================================

입력

pulsar-perf monitor-brokers --connect-string <zookeeper host:port>

출력 (모듈형 부하 관리자 예시 — 단기·장기 메시지 비율 포함)

===================================================================================================================
|||SYSTEM         |CPU %          |MEMORY %       |DIRECT %       |BW IN %        |BW OUT %       |MAX %          ||
|||               |0.00           |48.33          |0.01           |0.00           |0.00           |48.33          ||
|||COUNT          |TOPIC          |BUNDLE         |PRODUCER       |CONSUMER       |BUNDLE +       |BUNDLE -       ||
|||               |4              |4              |0              |2              |4              |0              ||
|||LATEST         |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |0.00           |0.00           |0.00           |0.00           |0.00           |0.00           ||
|||SHORT          |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |0.00           |0.00           |0.00           |0.00           |0.00           |0.00           ||
|||LONG           |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |0.00           |0.00           |0.00           |0.00           |0.00           |0.00           ||
===================================================================================================================

입력

pulsar-perf monitor-brokers --connect-string pulsar://<host:port> --extensions 

출력 (확장형 부하 관리자 예시)

===================================================================================================================
|||SYSTEM         |CPU %          |MEMORY %       |DIRECT %       |BW IN %        |BW OUT %       |MAX %          ||
|||               |17.24          |12.40          |26.95          |0.00           |0.00           |26.95          ||
|||COUNT          |TOPIC          |BUNDLE         |PRODUCER       |CONSUMER       |BUNDLE +       |BUNDLE -       ||
|||               |               |4              |               |               |               |               ||
|||LATEST         |MSG/S IN       |MSG/S OUT      |TOTAL          |KB/S IN        |KB/S OUT       |TOTAL          ||
|||               |100.02         |0.02           |100.03         |103.89         |0.01           |103.90         ||
===================================================================================================================

더 알아보기 (Learn more)