Capacity Planning, SLOs, and Error Budgets TODO
Concept
An SLO is a target set on a service-level indicator (SLI) measured from the user's perspective, and the error budget is the total amount of failure that target allows. If the availability target is set at 99.9%, the remaining 0.1% is the budget available for that period, and it becomes an explicit trade-off mechanism between shipping speed and stability. When budget remains you can deploy more aggressively; once it's exhausted, the policy is to halt feature releases and put the effort into reliability work instead. Capacity planning combines this with load forecasting to determine the maximum load the system can absorb while holding the target latency, and how much headroom is needed. From a queuing-theory perspective, wait time diverges sharply as utilization approaches 1, so headroom should be sized against peak and tail load, not average utilization.
Without agreeing on "how stable does this need to be" as a number, every priority fight between incident response and feature work turns into an emotional argument.
Code & Formula
# 용량 계획·SLO와 에러 예산 — 가용성 목표에서 허용 실패량(에러 예산)을 계산하고,
# 실측 실패율로 예산 소진율을 구해 배포를 계속할지 판단한다.
def error_budget_minutes(slo_percent, period_days=30):
"""기간 동안 허용되는 다운타임(분)"""
period_minutes = period_days * 24 * 60
allowed_failure_ratio = 1 - slo_percent / 100
return period_minutes * allowed_failure_ratio
def budget_status(slo_percent, downtime_minutes_so_far, days_elapsed, period_days=30):
total_budget = error_budget_minutes(slo_percent, period_days)
consumed_ratio = downtime_minutes_so_far / total_budget
# 지금까지 경과한 기간 대비 정상 소진 속도(1.0이면 딱 예산대로 소진 중)
expected_ratio_by_now = days_elapsed / period_days
burn_rate = consumed_ratio / expected_ratio_by_now if expected_ratio_by_now else 0
return total_budget, consumed_ratio, burn_rate
slo = 99.9 # 월 가용성 목표
total_budget = error_budget_minutes(slo)
print(f"SLO {slo}% -> 30일 에러 예산: {total_budget:.1f}분")
scenarios = [
("정상 운영", 10.0, 15), # 15일 경과, 다운타임 10분
("장애 다발", 35.0, 15), # 같은 15일에 다운타임 35분
]
for name, downtime, days in scenarios:
budget, consumed, burn = budget_status(slo, downtime, days)
action = "배포 계속 (여유 있음)" if burn < 1.0 else "기능 출시 중단, 신뢰성 작업 우선"
print(f"[{name}] {days}일 경과, 다운타임 {downtime}분 -> "
f"소진율 {consumed*100:.1f}%, burn rate {burn:.2f}x -> {action}")
# 용량 계획: 이용률이 1에 가까워질수록 대기시간이 급격히 발산 (M/M/1 근사)
def expected_wait_factor(utilization):
"""대기행렬 이론: 대기시간은 rho / (1 - rho) 에 비례해 발산"""
if utilization >= 1:
return float("inf")
return utilization / (1 - utilization)
print("\n이용률별 대기시간 배율 (M/M/1 근사):")
for rho in [0.5, 0.7, 0.9, 0.95, 0.99]:
print(f" rho={rho:.2f} -> wait factor={expected_wait_factor(rho):.2f}")
docs/code/algorithms/algorithms-49.py
Exercise
For a service you run, define two SLIs (availability and p99 latency), compute a 30-day SLO and error budget, then plug in the last 30 days of real measurements to work out the budget burn rate.
Practical Connection
For paths mixed with external factors — RPC node dependencies, oracle response latency, settlement transaction confirmation time — pre-defining targets and budgets is what lets you judge where "normal" ends.
Where it lands in Jayverse
- Devnet: define an SLO (availability + p99 latency) for the hosted Anvil devnet itself, since every service targets it. Track the 30-day error budget on gitboard so a single flaky devnet doesn't turn into a silent tax on every other service's reliability.
- Verex: set an explicit SLO/error budget for RPC and settlement-confirmation latency. Use the budget to gate feature releases vs reliability work — when it's exhausted, that's the trigger to stop shipping and fix the settlement path, not a judgment call each time.
- gitboard: surface error-budget burn rate as a first-class panel per service. That number, not a green/red badge, is what should decide "ship vs stabilize" across Rabbit, Verex, Wallet and Devnet.
Key expressions
| Expression | 뜻 · 쓰이는 자리 |
|---|---|
| error budget | 오류 예산(허용 가능한 장애 총량) · SLO에서 남은 실패 허용치를 가리킬 때 · "the error budget is the total amount of failure" |
| burn rate | 소진 속도 · 오류 예산이 얼마나 빨리 소모되는지 측정할 때 · "work out the budget burn rate" |
| headroom | 여유 용량 · 최대 부하 대비 시스템이 가진 여분을 가리킬 때 · "how much headroom is needed" |
| tail load | 꼬리 부하(피크·극단적으로 몰리는 부하) · 평균이 아니라 극단치 기준으로 설계할 때 · "headroom should be sized against peak and tail load" |
| diverges sharply | 급격히 발산하다·치솟다 · 이용률이 100%에 가까워질 때 대기시간이 폭증하는 현상 · "wait time diverges sharply as utilization approaches 1" |
| halt feature releases | 기능 출시를 중단하다 · 오류 예산이 소진되면 취하는 정책 · "the policy is to halt feature releases" |
| put the effort into | ~에 노력을 쏟다 · 안정성 작업으로 자원을 돌릴 때 · "put the effort into reliability work instead" |
| SLO | 서비스 수준 목표(Service-Level Objective) · SLI에 대해 설정하는 목표치, 오류 예산 산정의 기준 · "An SLO is a target set on a service-level indicator (SLI)" |
| SLI | 서비스 수준 지표(Service-Level Indicator) · 사용자 관점에서 측정하는 지표, SLO가 목표로 삼는 값 · "a service-level indicator (SLI) measured from the user's perspective" |
If you study this on a given day, add a note link and a ✅ to this line in the source curriculum (docs/knowledge/dev-100-curriculum.md) and this spot will lead straight to the note body. You can also write directly on this page — but regenerating overwrites it, so it's safer to keep anything you want to save as markdown under docs/algorithms/.