Skip to content

Consumers rate limiter

Subscribing user guide presents an overview of Consumers adaptive rate limiting algorithm. This section describes the algorithm in detail along with all configuration options that can be used to fine-tune it.

Measurement window for each subscription is LIMITER_PERIOD seconds. Each LIMITER_PERIOD seconds recalculation of output rate is triggered. There are three algorithm phases (modes), by default subscription is started in normal mode:

  • if there were no more than SPEEDUP_TOLERANCE% of failures, increase sending speed by CONVERGENCE_FACTOR%
  • if there was more than SPEEDUP_TOLERANCE% failures, but no more than TOLERANCE%, don't change output rate
  • if there was more than TOLERANCE% failures, decrease speed by CONVERGENCE_FACTOR%
  • if there was more than 50% of failures, enter slow mode

In slow mode requests are sent each SLOW_DELAY seconds:

  • if all requests were successful, enter normal mode
  • if more than 50% of requests was successful, do nothing
  • if more than 50% of requests failed, enter heartbeat mode

In heartbeat mode requests are sent each HEARTBEAT_DELAY seconds:

  • if all requests were successful, enter slow mode
  • if there were any failures, do nothing

Each of parameters written in capital letters can be configured:

Parameter name Option Default value
LIMITER_PERIOD consumer.rate.limiterSupervisorPeriod 30s
SPEEDUP_TOLERANCE consumer.rate.failuresSpeedUpToleranceRatio 0.01
TOLERANCE consumer.rate.failuresNoChangeToleranceRatio 0.05
CONVERGENCE_FACTOR consumer.rate.convergenceFactor 0.2
SLOW_DELAY consumer.rate.limiterSlowModeDelay 60s
HEARTBEAT_DELAY consumer.rate.limiterHeartbeatModeDelay 60s

How the negotiated algorithm works

By tracking latest RATE_HISTORY_SIZE DELIVERY_ATTEMPT_RATE samples, the algorithm is able to determine busy and non-busy consumers and balance the available global rate among them over time.

  • DELIVERY_ATTEMPT_RATE = sent_attempts / CONSUMER_MAX_RATE
  • We consider a consumer to be busy if it's DELIVERY_ATTEMPT_RATE > 1 - BUSY_TOLERANCE and we try to take away a bit of rate from others.
  • We don't bother do adjust more than MIN_CHANGE_PERCENT and we always preserve a MIN_MAX_RATE for a consumer.
  • Recalculation is done every BALANCE_INTERVAL seconds.
  • Consumer updates it's delivery attempt rate history every UPDATE_INTERVAL if the change from previous recorded value is greater than MIN_SIGNIFICANT_CHANGE_PERCENT.
  • MIN_SIGNIFICANT_CHANGE_PERCENT / 100 must be lower than BUSY_TOLERANCE, as otherwise consumers would (in some cases) not enter busy state
  • At the moment RATE_HISTORY_SIZE is ignored, defaulting to 1, and might be used in future versions of the algorithm
Parameter name Option Default value
BALANCE_INTERVAL consumer.maxrate.balanceInterval 30s
UPDATE_INTERVAL consumer.maxrate.updateInterval 15s
RATE_HISTORY_SIZE consumer.maxrate.historySize 1
BUSY_TOLERANCE consumer.maxrate.busyTolerance 0.1
MIN_MAX_RATE consumer.maxrate.minMaxRate 1.0
MIN_CHANGE_PERCENT consumer.maxrate.minAllowedChangePercent 1.0
MIN_SIGNIFICANT_CHANGE_PERCENT consumer.maxrate.minSignificantUpdatePercent 9.0