Horizontal Pod Autoscaler Replica Count
Problem Statement
The Horizontal Pod Autoscaler reads one metric per pod — average CPU utilisation, or queue depth, or inference latency — compares it to a target, and rescales the Deployment. Implement its control loop.
Background
The HPA formula is:
desiredReplicas = ceil(currentReplicas * (currentMetric / targetMetric))
Two details keep it from oscillating and from running away:
- Tolerance. If the ratio is within 10% of 1.0 — that is, abs(ratio - 1) <= 0.1 — the HPA does nothing and keeps currentReplicas. Without this, a service sitting at 51% against a 50% target would flap up and down forever.
- Clamping. The result is clamped into [minReplicas, maxReplicas].
The ceiling matters: scaling to 7.2 pods means 8 pods, because under-provisioning is the expensive mistake.
Your Task
Implement:
def hpa_desired(current_replicas, current_metric, target_metric, min_replicas, max_replicas):
Return the replica count as an int.
Input Format
- current_replicas: int, pods currently running.
- current_metric: number, the observed average metric value per pod.
- target_metric: number, the configured target.
- min_replicas, max_replicas: ints, the autoscaler bounds.
Output Format
- A single int.
Sample
print(hpa_desired(4, 90, 50, 1, 10))
Output:
8
The ratio is 1.8, well outside the tolerance band, so ceil(4 * 1.8) = 8 — within the [1, 10] bounds.
Example:
print(hpa_desired(4, 90, 50, 1, 10))
8
ratio = 90 / 50 = 1.8. abs(1.8 - 1) = 0.8 > 0.1, so the tolerance band does not apply. ceil(4 * 1.8) = ceil(7.2) = 8, and 8 lies inside [1, 10], so the HPA scales the Deployment to 8 pods.
Constraints:
- 0 <= current_replicas <= 1000, 1 <= min_replicas <= max_replicas <= 1000
- Metrics are non-negative numbers
- Tolerance band: no change when
abs(current_metric / target_metric - 1) <= 0.1 - Otherwise
ceil(current_replicas * ratio), then clamp into[min_replicas, max_replicas] - If
current_replicasortarget_metricis 0, returnmin_replicas - Return an int
1. Background Knowledge
The Horizontal Pod Autoscaler (HPA) is a core Kubernetes controller that automatically scales the number of pod replicas in a deployment, replication controller, or replica set based on observed metrics such as CPU utilization or custom application metrics. The primary goal is to maintain system stability and performance by ensuring that resources match demand. In machine learning systems, this is particularly critical for inference services where latency and throughput must remain within strict Service Level Objectives (SLOs).
The control logic relies on a feedback loop that compares the current metric (e.g., average CPU usage per pod) against a target metric (the desired usage level). If the current usage exceeds the target, the system scales up; if it is below, it scales down. However, naive scaling can lead to oscillation, where the system rapidly flips between scaling up and down due to minor fluctuations around the target. To prevent this, HPAs implement a tolerance band (often 10%) where no action is taken if the metric is close enough to the target.
Additionally, scaling decisions are constrained by clamping bounds (minReplicas and maxReplicas) to prevent resource exhaustion or under-provisioning. The calculation involves a ceiling function because fractional pods are not possible, and under-provisioning (rounding down) is generally more costly than over-provisioning (rounding up) in terms of latency spikes.
2. Algorithm Approach
The problem requires implementing a deterministic control loop based on a specific mathematical formula. The approach is direct computation with conditional logic for stability and bounds checking.
- Calculate Ratio: Determine the ratio of current_metric to target_metric.
- Check Tolerance: Evaluate if the ratio is within the acceptable tolerance band (typically ±10% of 1.0). If it is, return the current_replicas unchanged to prevent flapping.
- Compute Desired Replicas: If outside the tolerance, apply the HPA formula: desired=⌈current_replicas×ratio⌉.
- Clamp Result: Ensure the final result lies within the [min_replicas, max_replicas] range.
This approach avoids complex iterative algorithms or simulations, relying instead on precise arithmetic and boundary checks.
3. Step-by-Step Strategy
- Handle Edge Cases: Although the problem implies valid inputs, ensure target_metric is not zero to avoid division errors. If target_metric is 0, the behavior is undefined in standard HPA, but for this problem, assume valid positive inputs.
- Compute the Ratio: Calculate ratio = current_metric / target_metric.
- Apply Tolerance Check:
- The tolerance condition is abs(ratio - 1.0) <= 0.1.
- If this condition is True, the system is stable. Return current_replicas.
- Calculate Raw Desired Replicas:
- Use the formula: raw_desired = current_replicas * ratio.
- Apply the ceiling function: desired = ceil(raw_desired). In Python, use math.ceil().
- Clamp the Value:
- Ensure desired is at least min_replicas.
- Ensure desired is at most max_replicas.
- This can be done using max(min_replicas, min(max_replicas, desired)).
- Return Result: Cast the final result to an integer and return it.
4. Common Pitfalls
- Floating Point Precision: When checking abs(ratio - 1.0) <= 0.1, be aware of floating-point inaccuracies. While standard float precision is usually sufficient for this problem, always use math.ceil rather than integer casting (int()) for the final calculation, as (int()) truncates towards zero (floor for positive numbers), which violates the "under-provisioning is expensive" rule.
- Tolerance Logic Error: A common mistake is checking if current_metric is within 10% of target_metric directly. The problem specifies the ratio must be within 10% of 1.0. These are mathematically equivalent, but implementing the ratio check explicitly reduces confusion.
- Clamping Order: Ensure clamping happens after the ceiling operation. Clamping before ceiling could result in a value that, when ceiled, exceeds max_replicas.
- Integer Division: In Python 3, / performs float division. Ensure you are not accidentally using integer division // for the ratio calculation, which would yield incorrect results for non-integer ratios.
- Missing Imports: Remember to import math for math.ceil.
5. Time & Space Complexity
- Time Complexity: O(1). The solution involves a constant number of arithmetic operations (division, multiplication, absolute value, ceiling) and comparisons. It does not depend on the size of any input data structure, only on the numerical values provided.
- Space Complexity: O(1). The algorithm uses a fixed amount of extra space for variables (ratio, desired, etc.), regardless of input size. No additional data structures are allocated.