Class FeedbackAdaptiveRateLimiter
Core Algorithm: This rate limiter divides time into fixed refill intervals (configurable
via hbase.quota.rate.limiter.refill.interval.ms, default is 1 refill per TimeUnit of the
RateLimiter). At the beginning of each interval, a fresh allocation of resources becomes
available based on the configured limit. Clients consume resources as they make requests. When
resources are exhausted, clients must wait until the next refill, or until enough resources
become available.
Adaptive Backpressure: When multiple threads compete for limited resources (contention),
this limiter detects the contention and applies increasing backpressure by extending wait
intervals. This prevents thundering herd behavior where many threads wake simultaneously and
compete for the same resources. The backoff multiplier increases by a small increment (see
FEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_INCREMENT) per interval when contention occurs, and
decreases (see FEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_DECREMENT) when no contention is
detected, converging toward optimal throughput. The multiplier is capped at a maximum value (see
FEEDBACK_ADAPTIVE_MAX_BACKOFF_MULTIPLIER) to prevent unbounded waits.
Contention is detected when getWaitInterval(long, long, long) is called with insufficient available
resources (i.e., amount > available), indicating a thread needs to wait for resources. If
this occurs more than once in a refill interval, the limiter identifies it as contention
requiring increased backpressure.
Oversubscription for Full Utilization: In practice, synchronization overhead and timing
variations often prevent clients from consuming exactly their full allowance, resulting in
consistent under-utilization. This limiter addresses this by tracking utilization via an
exponentially weighted moving average (EWMA). When average utilization falls below the target
range (determined by FEEDBACK_ADAPTIVE_UTILIZATION_ERROR_BUDGET), the limiter gradually
increases the oversubscription proportion (see
FEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_INCREMENT), allowing more resources per interval than
the base limit. Conversely, when utilization exceeds the target range, oversubscription is
decreased (see FEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_DECREMENT). Oversubscription is capped
(see FEEDBACK_ADAPTIVE_MAX_OVERSUBSCRIPTION) to prevent excessive bursts while still
enabling consistent full utilization.
Example Scenario: Consider a quota of 1000 requests per second with a 1-second refill interval. Without oversubscription, clients might typically achieve only 950 req/s due to coordination delays. This limiter would detect the under-utilization, gradually increase oversubscription, allowing slightly more resources per interval, which compensates for inefficiencies and achieves stable throughput closer to the configured quota. If multiple threads simultaneously try to consume resources and repeatedly wait, the backoff multiplier increases their wait times, spreading out their retry attempts and reducing wasted CPU cycles.
Configuration Parameters:
FEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_INCREMENT: Controls rate of backpressure increaseFEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_DECREMENT: Controls rate of backpressure decreaseFEEDBACK_ADAPTIVE_MAX_BACKOFF_MULTIPLIER: Caps the maximum wait time extensionFEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_INCREMENT: Controls rate of oversubscription increaseFEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_DECREMENT: Controls rate of oversubscription decreaseFEEDBACK_ADAPTIVE_MAX_OVERSUBSCRIPTION: Caps the maximum burst capacityFEEDBACK_ADAPTIVE_UTILIZATION_ERROR_BUDGET: Defines the acceptable range around full utilization
This algorithm converges toward stable operation where: (1) wait intervals are just long enough to prevent excessive contention, and (2) oversubscription is just high enough to achieve consistent full utilization of the configured allowance.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic class -
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final doubleprivate final doubleprivate final org.apache.hbase.thirdparty.com.google.common.util.concurrent.AtomicDoublestatic final doublestatic final doublestatic final doublestatic final doublestatic final doublestatic final doublestatic final doubleprivate final doublestatic final StringAmount to decrease the backoff multiplier when no contention is detected per refill interval.static final StringAmount to increase the backoff multiplier when contention is detected per refill interval.static final StringMaximum ceiling for the backoff multiplier to avoid unbounded waits.static final StringMaximum ceiling for oversubscription to prevent unbounded bursts.static final StringAmount to decrease the oversubscription proportion when utilization exceeds (1.0+errorBudget).static final StringAmount to increase the oversubscription proportion when utilization is below (1.0-errorBudget).static final StringAcceptable deviation around full utilization (1.0) for adjusting oversubscription.private booleanprivate final AtomicLongprivate final doubleprivate final doubleprivate final doubleprivate final doubleprivate longprivate final doubleprivate final doubleprivate final org.apache.hbase.thirdparty.com.google.common.util.concurrent.AtomicDoubleprivate final longprivate doubleprivate static final intFields inherited from class org.apache.hadoop.hbase.quotas.RateLimiter
DEFAULT_TIME_UNIT, QUOTA_RATE_LIMITER_CONF_KEY -
Constructor Summary
ConstructorsConstructorDescriptionFeedbackAdaptiveRateLimiter(long refillInterval, double backoffMultiplierIncrement, double backoffMultiplierDecrement, double maxBackoffMultiplier, double oversubscriptionIncrement, double oversubscriptionDecrement, double maxOversubscription, double utilizationErrorBudget) -
Method Summary
Modifier and TypeMethodDescriptionprivate longapplyBackoffMultiplier(long baseWaitInterval) voidconsume(long amount) consume amount available units, amount could be a negative numberlongprivate longgetOversubscribedLimit(long limit) private longgetRefillIntervalAdjustedLimit(long limit) longgetWaitInterval(long limit, long available, long amount) Time in milliseconds to wait for before requesting to consume 'amount' resource.longrefill(long limit) Refill the available units w.r.t the elapsed time.voidsetNextRefillTime(long nextRefillTime) Methods inherited from class org.apache.hadoop.hbase.quotas.RateLimiter
consume, getAvailable, getLimit, getTimeUnitInMillis, getWaitIntervalMs, getWaitIntervalMs, isAvailable, isBypass, set, toString, update, waitInterval, waitInterval
-
Field Details
-
FEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_INCREMENT
Amount to increase the backoff multiplier when contention is detected per refill interval. In other words, if we are throttling more than once per refill interval, then we will increase our wait intervals (increase backpressure, decrease throughput).- See Also:
-
DEFAULT_BACKOFF_MULTIPLIER_INCREMENT
- See Also:
-
FEEDBACK_ADAPTIVE_BACKOFF_MULTIPLIER_DECREMENT
Amount to decrease the backoff multiplier when no contention is detected per refill interval. In other words, if we are only throttling once per refill interval, then we will decrease our wait interval (decrease backpressure, increase throughput).- See Also:
-
DEFAULT_BACKOFF_MULTIPLIER_DECREMENT
- See Also:
-
FEEDBACK_ADAPTIVE_MAX_BACKOFF_MULTIPLIER
Maximum ceiling for the backoff multiplier to avoid unbounded waits.- See Also:
-
DEFAULT_MAX_BACKOFF_MULTIPLIER
- See Also:
-
FEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_INCREMENT
Amount to increase the oversubscription proportion when utilization is below (1.0-errorBudget).- See Also:
-
DEFAULT_OVERSUBSCRIPTION_INCREMENT
- See Also:
-
FEEDBACK_ADAPTIVE_OVERSUBSCRIPTION_DECREMENT
Amount to decrease the oversubscription proportion when utilization exceeds (1.0+errorBudget).- See Also:
-
DEFAULT_OVERSUBSCRIPTION_DECREMENT
- See Also:
-
FEEDBACK_ADAPTIVE_MAX_OVERSUBSCRIPTION
Maximum ceiling for oversubscription to prevent unbounded bursts. Some oversubscription can be nice, because it allows you to balance the inefficiency and latency of retries, landing on stable usage at approximately your configured allowance. Without adequate oversubscription, your steady state may often seem significantly, and suspiciously, lower than your configured allowance.- See Also:
-
DEFAULT_MAX_OVERSUBSCRIPTION
- See Also:
-
FEEDBACK_ADAPTIVE_UTILIZATION_ERROR_BUDGET
Acceptable deviation around full utilization (1.0) for adjusting oversubscription. If stable throttle usage is typically under (1.0-errorBudget), then we will allow more oversubscription. If stable throttle usage is typically over (1.0+errorBudget), then we will pull back oversubscription.- See Also:
-
DEFAULT_UTILIZATION_ERROR_BUDGET
- See Also:
-
WINDOW_TIME_MS
- See Also:
-
nextRefillTime
-
refillInterval
-
backoffMultiplierIncrement
-
backoffMultiplierDecrement
-
maxBackoffMultiplier
-
oversubscriptionIncrement
-
oversubscriptionDecrement
-
maxOversubscription
-
minTargetUtilization
-
maxTargetUtilization
-
currentBackoffMultiplier
private final org.apache.hbase.thirdparty.com.google.common.util.concurrent.AtomicDouble currentBackoffMultiplier -
hadContentionThisInterval
-
oversubscriptionProportion
private final org.apache.hbase.thirdparty.com.google.common.util.concurrent.AtomicDouble oversubscriptionProportion -
emaAlpha
-
utilizationEma
-
lastIntervalConsumed
-
-
Constructor Details
-
FeedbackAdaptiveRateLimiter
FeedbackAdaptiveRateLimiter(long refillInterval, double backoffMultiplierIncrement, double backoffMultiplierDecrement, double maxBackoffMultiplier, double oversubscriptionIncrement, double oversubscriptionDecrement, double maxOversubscription, double utilizationErrorBudget)
-
-
Method Details
-
refill
Description copied from class:RateLimiterRefill the available units w.r.t the elapsed time.- Specified by:
refillin classRateLimiter- Parameters:
limit- Maximum available resource units that can be refilled to.- Returns:
- how many resource units may be refilled ?
-
getOversubscribedLimit
-
consume
Description copied from class:RateLimiterconsume amount available units, amount could be a negative number- Overrides:
consumein classRateLimiter- Parameters:
amount- the number of units to consume
-
getWaitInterval
Description copied from class:RateLimiterTime in milliseconds to wait for before requesting to consume 'amount' resource.- Specified by:
getWaitIntervalin classRateLimiter- Parameters:
limit- Maximum available resource units that can be refilled to.available- Currently available resource unitsamount- Resources for which time interval to calculate for- Returns:
- estimate of the ms required to wait before being able to provide 'amount' resources.
-
getRefillIntervalAdjustedLimit
-
applyBackoffMultiplier
-
setNextRefillTime
- Specified by:
setNextRefillTimein classRateLimiter
-
getNextRefillTime
- Specified by:
getNextRefillTimein classRateLimiter
-