메시지 전달 스로틀링

메시지 전달 스로틀링 (Message Dispatch Throttling)

큰 메시지 페이로드가 쌓이면 메모리 사용량이 치솟아 성능이 떨어질 수 있어요. Pulsar는 메시지 전달(dispatch)에 속도 제한(rate-limit) 스로틀링 메커니즘을 적용해 트래픽 급증을 막고 메시지 전달성을 높여줘요. 이 글에서는 스로틀링이 무엇이고 왜 필요한지, 어떤 수준과 방식으로 설정하는지, 그리고 설정할 때 알아야 할 한계까지 정리해 드릴게요.

출처: 문서

본문

개요

메시지 전달 스로틀링이란 무엇인가요?

큰 메시지 페이로드는 메모리 사용량 급증을 일으켜 성능 저하로 이어질 수 있어요. Pulsar는 메시지 전달에 속도 제한 스로틀링 메커니즘을 채택해 트래픽 급증을 피하고 메시지 전달성을 높여요. 클라이언트에 전달할 수 있는 메시지 수와 엔트리의 바이트 크기를 제한하는 임계값을 설정할 수 있고, 단위 시간당 트래픽이 임계값을 초과하면 이후 전달을 차단해요.

예를 들어 전달 속도 제한을 초당 10개 메시지로 구성하면, 클라이언트에 초당 전달할 수 있는 메시지 수는 최대 10개예요.

왜 메시지 전달 스로틀링을 사용하나요?

메시지 전달 스로틀링은 자세히 보면 다음과 같은 이점을 제공해요:

  • BookKeeper에 대한 브로커의 읽기 요청 부하 제한 메시지는 BookKeeper 클러스터에 영구 저장돼요. 캐시된 데이터로 많은 읽기 요청을 처리할 수 없으면 BookKeeper 클러스터가 응답하기에 너무 바빠질 수 있고, 브로커의 I/O나 CPU 리소스가 완전히 점유될 수 있어요. 메시지 전달 스로틀링 기능으로 데이터 흐름을 조절해 BookKeeper에 대한 브로커의 읽기 요청 부하를 제한할 수 있어요.
  • 토픽/구독 수준에서 브로커 하드웨어 리소스 할당 균형화 브로커 인스턴스는 여러 토픽을 동시에 서비스해요. 토픽 하나가 요청으로 과부하되면 브로커의 I/O, CPU, 메모리 리소스를 거의 모두 소비해 다른 토픽을 읽지 못하게 할 수 있어요. 메시지 전달 스로틀링 기능으로 브로커 하드웨어 리소스가 토픽 간에 어떻게 할당되는지를 제한할 수 있어요.
  • 토픽/구독 수준에서 클라이언트 하드웨어 리소스 할당 제한 소비할 백로그 메시지가 많으면 클라이언트가 짧은 시간에 많은 데이터를 받아 자신의 컴퓨팅 리소스를 독점할 수 있어요. 클라이언트에는 소비 속도를 능동적으로 제한하는 메커니즘이 없으므로, 메시지 전달 스로틀링 기능이 클라이언트 하드웨어 리소스의 할당도 조절할 수 있어요.

메시지 전달 스로틀링은 어떻게 동작하나요?

메시지 전달 스로틀링 과정은 다음 단계로 나눌 수 있어요:

  1. 브로커가 남은 할당량(quota)을 계산해 bookies에서 읽을 엔트리 수를 근사해요.
  2. 브로커가 bookies에서 메시지를 읽어요.
  3. 브로커가 클라이언트에 메시지를 전달하고 카운터를 갱신해 할당량을 줄여요. 예약된 작업이 스로틀링 주기가 끝나면 할당량을 새로 고쳐요.

참고

  • 브로커는 데이터를 읽기 전까지 엔트리당 실제 메시지 수나 실제 엔트리 크기를 알 수 없으므로, 3단계 전에는 할당량을 줄일 수 없어요.
  • seek이나 redeliver 같은 작업은 메시지를 클라이언트에 여러 번 전달할 수 있어요. 브로커는 이를 서로 다른 메시지로 계산해 카운터를 갱신해요.

개념

스로틀링 수준

스로틀 메시지 전달은 서로 다른 수준에서 설정할 수 있어요.

수준 설명
브로커별 (Per broker) 단일 브로커의 모든 구독이 할당량을 공유해요.
토픽별 (Per topic) 같은 토픽의 모든 구독이 할당량을 공유해요. 비파티션 토픽이라면 할당량은 토픽이 단위 시간당 전달할 수 있는 최대 메시지 수와 같아요. 토픽에 여러 파티션이 있으면 할당량은 각 파티션이 단위 시간당 전달할 수 있는 최대 메시지 수를 의미해요. 즉 파티션 토픽의 실제 전달 속도 제한은 설정한 값의 N배가 돼요 (N은 토픽 안의 파티션 수). 예를 들어 토픽 t0에 두 개의 파티션이 있어요. 할당량을 10/s로 설정하면 t0-p0t0-p1의 속도 제한이 각각 10/s가 되고, t0의 전체 속도 제한은 20/s가 돼요. 할당량은 파티션 간에는 공유할 수 없지만, 파티션 안의 구독 간에는 공유할 수 있다는 점에 유의하세요.
구독별 (Per subscription) 비파티션 토픽이라면 속도 제한은 구독이 단위 시간당 클라이언트에 전달할 수 있는 최대 메시지 수를 의미해요. 구독 중인 토픽에 여러 파티션이 있으면 속도 제한은 구독이 단위 시간당 파티션별로 전달할 수 있는 최대 메시지 수를 의미해요. 즉 파티션 토픽에 대한 구독의 실제 전달 속도 제한은 설정한 값의 N배가 돼요 (N은 토픽 안의 파티션 수). 예를 들어 토픽 t1에 두 개의 파티션이 있고 구독 s1이 있어요. 속도 제한을 10/s로 설정하면 t1-p0t1-p1에서 s1의 속도 제한이 각각 10/s가 되고, s1의 전체 속도 제한은 20/s가 돼요.

참고 여러 수준에서 구성된 전달 속도 제한은 동시에 적용돼요 (논리적 AND).

스로틀링 방식

다양한 수준에서 전달 속도 제한을 구성하기 위해 여러 스로틀링 방식을 사용할 수 있어요.

방식 클러스터별 토픽별 구독별
브로커 구성 또는 동적 브로커 구성 설정 dispatchThrottlingRateInMsg``dispatchThrottlingRateInByte dispatchThrottlingRatePerTopicInMsg``dispatchThrottlingRatePerTopicInByte 클러스터의 모든 토픽에 적용돼요. dispatchThrottlingRatePerSubscriptionInMsg``dispatchThrottlingRatePerSubscriptionInByte 클러스터의 모든 구독에 적용돼요.
네임스페이스 정책 설정 N/A 토픽 전달 스로틀링 구성 참조 구독 전달 스로틀링 구성 참조
토픽 정책 설정 N/A 토픽 수준 전달 속도 설정 참조 구독 수준 전달 속도 설정 참조. 토픽의 모든 구독에 적용돼요.

참고 위 세 가지 방식을 통해 구성된 전달 속도 제한은 우선순위가 적용돼요. "토픽 정책" > "네임스페이스 정책" > "브로커 구성" 순서예요. 예를 들어 세 가지 방식을 모두 사용해 구독 전달 속도 제한을 구성했다면, "토픽 정책"으로 구성한 것만 적용돼요.

스로틀링 구성

다음 표는 conf/broker.conf 파일에서 메시지 전달 스로틀링에 대해 구성할 수 있는 파라미터를 정리한 거예요.

파라미터 설명 기본값
dispatchThrottlingRateInMsg 스로틀링 주기당 클러스터별로 전달할 수 있는 총 메시지 수예요. 토픽 수준이나 구독 수준을 설정하려면 dispatchThrottlingRatePerTopicInMsg 또는 dispatchThrottlingRatePerSubscriptionInMsg를 구성하세요. '-1', 제한 없음을 의미해요.
dispatchThrottlingRateInByte 스로틀링 주기당 클러스터별로 전달할 수 있는 총 바이트 크기예요. 토픽 수준이나 구독 수준을 설정하려면 dispatchThrottlingRatePerTopicInByte 또는 dispatchThrottlingRatePerSubscriptionInByte를 구성하세요. '-1', 제한 없음을 의미해요.
ratePeriodInSecond 전달 스로틀링 기간(초)이에요. 카운터는 주기가 끝날 때 초기화돼요. 예를 들어 속도 제한을 분당 10,000개 메시지로 구성하려면 ratePeriodInSecond60으로, dispatchThrottlingRateInMsg10,000으로 설정해야 해요. 1 (초)
preciseDispatcherFlowControl 전달 스로틀링에 정밀한 제어를 적용할지 여부예요. 기본적으로 비활성화되어 있으며, 이 경우 브로커는 남은 consumer.receiverQueueSize(기본 1000)와 dispatcherMaxReadBatchSize(기본 100) 중 최솟값을 사용해 bookies에서 읽을 메시지 수를 근사해요. true로 설정하면 브로커는 다음 방정식으로 bookies에서 읽을 엔트리 수를 근사해요: bookies에서 읽을 엔트리 수 = 읽을 메시지 수 / 엔트리당 평균 메시지 수. 예를 들어 속도 제한을 10/s로 설정했다고 해볼게요. 엔트리당 평균 메시지 수가 6이면 브로커가 초당 2개 엔트리를 읽는다는 뜻이고, 읽을 총 메시지 수가 할당량을 초과해요. 하지만 false로 설정하면 브로커가 10개 엔트리(약 60개 메시지)를 읽어 할당량을 훨씬 더 많이 초과해요. false
dispatchThrottlingOnBatchMessageEnabled 메시지를 엔트리(배치) 단위로 계산할지 여부예요. 기본적으로 비활성화되어 있어요. true로 설정하면 총 메시지 수의 근사값이 부정확해질 수 있지만, bookies에 대한 안정적인 읽기 요청을 유지하면서 Pulsar의 처리량을 최대화할 수 있다는 점에 유의하세요. 예를 들어 속도 제한을 10/s로 설정했다고 해볼게요. dispatchThrottlingOnBatchMessageEnabledtrue로 설정하면 엔트리당 메시지 수와 무관하게 브로커는 초당 10개 엔트리만 읽어 클라이언트에 전달해요. false
dispatchThrottlingOnNonBacklogConsumerEnabled 비백로그 소비자에 대한 전달 스로틀링을 활성화할지 여부예요. 기본적으로 활성화되어 있어요. false로 설정하면: 한 구독의 모든 소비자에게 백로그가 없으면 dispatchThrottlingRateInMsgdispatchThrottlingRateInByte가 구성되어 있어도 메시지 전달 스로틀링이 자동으로 꺼져요. 소비자 중 하나라도 백로그가 있으면 스로틀링이 자동으로 켜져요. true

참고

  • dispatchThrottlingRateInMsg와 dispatchThrottlingRateInByte를 동시에 사용할 수 있어요 (논리적 AND).
  • preciseDispatcherFlowControl와 dispatchThrottlingOnBatchMessageEnabled는 상호 배타적이므로 한 번에 하나만 활성화해야 해요. 두 파라미터 모두 초과 전달 문제(한계 참조)를 개선하는 데 사용할 수 있어요. 차이점은: preciseDispatcherFlowControl가 활성화되면 Pulsar가 엔트리당 메시지 수를 고려해요. 이 파라미터는 브로커가 bookies에서 엔트리를 읽을 때 적용돼요. dispatchThrottlingOnBatchMessageEnabled가 활성화되면 Pulsar가 엔트리당 메시지 수를 무시해요. 이 파라미터는 브로커가 클라이언트에 메시지를 보낸 후 카운터를 갱신할 때 적용돼요.

메시지 전달 스로틀링의 한계

메시지 전달 스로틀링은 다음과 같은 이유로 단위 시간당 메시지가 초과 전달될 수 있어요:

  1. 브로커가 스로틀링 한도보다 더 많은 엔트리나 바이트를 bookies에서 읽을 수 있어요. a) 클라이언트에 전달되는 메시지의 바이트 크기가 구성된 임계값을 초과할 수 있어요. 바이트/스로틀링-주기로 전달 속도 제한(dispatchThrottlingRateInByte/ratePeriodInSecond)을 설정하면, 브로커는 다음 방정식으로 한 스로틀링 주기 안의 bookies에서 읽을 엔트리 수를 계산해요: bookies에서 읽을 엔트리 수 = 읽을 총 바이트 크기 / 엔트리당 평균 바이트 크기. bookies에서 읽을 엔트리 수를 제어함으로써 브로커는 각 스로틀링 주기 안에 읽을 총 바이트 크기전달 속도 아래로 제한하려 해요. 브로커는 엔트리 단위로 bookies에서 메시지를 읽으며, 읽기 전에는 각 엔트리의 정확한 바이트 크기를 모르므로 다음에 읽을 엔트리의 바이트를 근사해요. 브로커는 엔트리당 평균 바이트 크기를 얻기 위해 다음 두 지표를 사용해요:
    • 평균 게시 크기(brk_ml_EntrySizeBuckets): 브로커가 게시 요청을 받았을 때 bookies에 저장된 엔트리당 평균 바이트 크기예요.
    • 평균 전달 크기(entriesReadSize/entriesReadCount): bookies에서 읽은 엔트리당 평균 바이트 크기, 즉 클라이언트에 보낸 엔트리당 평균 바이트 크기예요. 브로커는 평균 전달 크기보다 평균 게시 크기를 우선 사용해요. 평균 게시 크기를 사용할 수 없으면 평균 전달 크기를 사용해요. 두 지표 모두 사용할 수 없으면 브로커는 첫 시도에서 엔트리 하나만 읽어요. b) 클라이언트에 전달되는 메시지 수가 구성된 임계값을 초과할 수 있어요. 메시지 수/스로틀링-주기로 전달 속도 제한(dispatchThrottlingRateInMsg/ratePeriodInSecond)을 설정하고 배칭(batch-send)이 활성화되면, 브로커는 엔트리를 하나의 메시지로 계산하고(엔트리당 메시지 수와 무관하게) 다음 방정식으로 bookies에서 읽을 엔트리 수를 계산해요: bookies에서 읽을 엔트리 수 = 읽을 총 메시지 수 / 엔트리당 평균 메시지 수 (=1). 엔트리당 메시지가 여러 개이므로 클라이언트에 전달되는 메시지 수는 항상 구성된 임계값을 초과하거나 같아요. 해결 방법 preciseDispatcherFlowControl 또는 dispatchThrottlingOnBatchMessageEnabled를 구성하면 초과 전달 문제를 완화할 수 있어요. 예를 들어 preciseDispatcherFlowControl를 켜면 근사된 엔트리당 평균 메시지 수로 할당량을 미리 감소시켜 이 한계를 완화할 수 있어요. 자세한 내용은 스로틀링 구성을 보세요.
  2. 동시 스로틀링 프로세스가 할당량을 제때 줄이지 못할 수 있어요. 동작 방식에서 소개한 대로 전달 스로틀링 과정은 1.남은 할당량 얻기2.데이터 로드3.할당량 감소예요. 같은 구독에서 "재생 메시지 전달(process-R)"과 "비재생 메시지 전달(process-N)"이라는 두 프로세스가 동시에 실행되면, 그 스로틀링 과정이 다음 순서로 서로 엮일 수 있어요:
    1. process-R: 1. 남은 할당량 얻기
    2. process-R: 2. 데이터 로드
    3. process-N: 1. 남은 할당량 얻기
    4. process-N: 2. 데이터 로드
    5. process-R: 3. 할당량 감소
    6. process-N: 3. 할당량 감소 결과적으로 전달된 총 메시지 수가 할당량을 초과할 수 있어요.

    참고 초과 전달이 발생해 현재 주기의 전달 메시지 수가 할당량을 초과하면 다음 주기의 할당량은 그만큼 줄어요. 예를 들어 속도 제한이 10/s로 설정되어 있는데 첫 주기에 11개 메시지가 클라이언트에 전달되면, 다음 주기에는 최대 9개 메시지만 전달할 수 있어요. 마지막 주기에 30개 메시지가 전달됐다면 다음 두 주기의 전달 메시지 수는 0이에요.

더 알아보기 (Learn more)