ЁЯПл The SchoolтА║ЁЯЫая╕П SREтА║ЁЯФв рдзрдбрд╛ 09 тАФ Reliability math: рд╕рд╛рдЦрд│реНрдпрд╛, рдкреНрд░рддреА рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ nine рдЪреА рдХрд┐рдВрдордд
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯФв рдзрдбрд╛ 09 тАФ Reliability math: рд╕рд╛рдЦрд│реНрдпрд╛, рдкреНрд░рддреА рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ nine рдЪреА рдХрд┐рдВрдордд

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 09 ┬╖ рдорд╛рдЧреЗ: lesson-08-incident-command ┬╖ рдкреБрдвреЗ: lesson-10-overload


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рднрд╛рдЧ 3 рд╕реБрд░реВ рд╣реЛрддреЛ: рдЕрдкрдпрд╢ рдЧреГрд╣реАрдд рдзрд░реВрди design. рдХрд╛рд╣реАрд╣реА рдмрд╛рдВрдзрдгреНрдпрд╛рдЖрдзреА рдЧрдгрд┐рдд рдХрд░рд╛. рд░рд╛рдВрдЧреЗрддреАрд▓ (serial) рднрд╛рдЧ рддреНрдпрд╛рдВрдЪреА availability рдЧреБрдгрд╛рдХрд╛рд░рд╛рдиреЗ рдХрдореА рдХрд░рддрд╛рдд; рд╕реНрд╡рддрдВрддреНрд░ рдкреНрд░рддреА (parallel) nines рд╡рд╛рдврд╡рддрд╛рдд. рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдЬрд╛рд╕реНрддреАрдЪрд╛ nine рджрд╣рд╛рдкрдЯ рдХрдореА downtime рдареЗрд╡рддреЛ тАФ рд▓рд╡рдХрд░рдЪ рддреЛ рдПрдЦрд╛рджреНрдпрд╛ рд╡реНрдпрдХреНрддреАрд▓рд╛ рдкреНрд░рддрд┐рд╕рд╛рдж рджреНрдпрд╛рдпрд▓рд╛ рд▓рд╛рдЧрдгрд╛рд▒реНрдпрд╛ рд╡реЗрд│реЗрдкреЗрдХреНрд╖рд╛рд╣реА рдХрдореА рд╣реЛрддреЛ. sre/design.py рдордзреАрд▓ serial, parallel рдЖрдгрд┐ downtime рдЖрдгрд┐ sre/demo.py рдордзреАрд▓ nines().

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рд╡реЗрд│рд╛рдкрддреНрд░рдХрд╛рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрд╛рдпрд▓рд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдерд┐рдиреА рд░рд╛рдВрдЧреЗрддреАрд▓ рддреАрди рджрд╛рд░рд╛рдВрддреВрди рдЬрд╛рддреЗ: рдлрд╛рдЯрдХ, рд╕рднрд╛рдЧреГрд╣рд╛рдЪреЗ рджрд╛рд░ рдЖрдгрд┐ office рдЪреЗ рджрд╛рд░. ЁЯЪкЁЯЪкЁЯЪк рдХреЛрдгрддреЗрд╣реА рдПрдХ рджрд╛рд░ рдЕрдбрдХрд▓реЗ, рддрд░ рддреА рдЖрдд рдЬрд╛рдК рд╢рдХрдд рдирд╛рд╣реА.

рдлрд╛рдЯрдХ 99.99% рд╡реЗрд│ рдЪрд╛рд▓рддреЗ, рд╕рднрд╛рдЧреГрд╣рд╛рдЪреЗ рджрд╛рд░ 99.95%, office рдЪреЗ рджрд╛рд░ 99.9%. рддрд┐рдиреНрд╣реА рдорд┐рд│реВрди? рддреБрдореНрд╣реА рдЧреБрдгрд╛рдХрд╛рд░ рдХрд░рддрд╛: 99.84%. рд╣реЗ рд╕рд░реНрд╡рд╛рдд рд╡рд╛рдИрдЯ рджрд╛рд░рд╛рдкреЗрдХреНрд╖рд╛рд╣реА рд╡рд╛рдИрдЯ рдЖрд╣реЗ. рддреБрдореНрд╣реА рдЬреЛрдбрд▓реЗрд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рджрд╛рд░ рдкреНрд░рд╡рд╛рд╕ рдХрдореА рд╡рд┐рд╢реНрд╡рд╛рд╕рд╛рд░реНрд╣ рдХрд░рддреЗ.

рдЖрддрд╛ рдкрдердХ рдкрд╣рд┐рд▓реНрдпрд╛ рджрд╛рд░рд╛рдЪреНрдпрд╛ рдЕрдЧрджреА рд╢реЗрдЬрд╛рд░реА office рдЪреЗ рджреБрд╕рд░реЗ рджрд╛рд░ рдмрд╛рдВрдзрддреЗ. рдПрдХ рдЕрдбрдХрд▓реЗ, рддрд░ рддреБрдореНрд╣реА рджреБрд╕рд░реЗ рд╡рд╛рдкрд░рддрд╛. рджреЛрдиреНрд╣реА рдПрдХрд╛рдЪ рдХреНрд╖рдгреА рдЕрдбрдХрд▓реА рддрд░рдЪ рджреЛрдиреНрд╣реА рдмрдВрдж тАФ рдЖрдгрд┐ рд╣реЗ рдлрд╛рд░ рдХреНрд╡рдЪрд┐рдд рдШрдбрддреЗ (рдЬреЛрдкрд░реНрдпрдВрдд рддреНрдпрд╛рдВрдирд╛ рдПрдХрдЪ рдХреБрд▓реВрдк рдирд╛рд╣реА!). Office 99.9999% рд╣реЛрддреЗ, рдЖрдгрд┐ рд╕рдВрдкреВрд░реНрдг рдкреНрд░рд╡рд╛рд╕ 99.94% рд╣реЛрддреЛ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    u["ЁЯСйтАНЁЯОУ pupil"] --> g["gateway<br/>99.99%"] --> a["timetable app<br/>99.95%"] --> d["database<br/>99.9%"]
    d --> r1["serial: 99.84%<br/>14.0 h a year"]
    a --> d1["db copy 1<br/>99.9%"]
    a --> d2["db copy 2<br/>99.9%"]
    d1 & d2 --> r2["parallel: 99.9999%<br/>chain 99.94%"]

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/sre/lesson-diagrams.html#l09

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг SLOs (рдзрдбрд╛ 02) рд╣реА рд╡рдЪрдиреЗ рдЖрд╣реЗрдд, рдЖрдгрд┐ рд╡рдЪрди рджреЗрдгреНрдпрд╛рдЪреНрдпрд╛ рдЖрдзреА рддреЗ рд╢рдХреНрдп рддрд░реА рдЖрд╣реЗ рдХрд╛ рд╣реЗ рдЕрд╕реЗ рддрдкрд╛рд╕рддрд╛рдд. рдЧреБрдгрд╛рдХрд╛рд░рд╛рдиреЗ 99.84% рд╣реЛрдгрд╛рд▒реНрдпрд╛ рд╕рд╛рдЦрд│реАрд╡рд░ 99.9% SLO рдореНрд╣рдгрдЬреЗ design рдкрд╛рд│реВ рд╢рдХрдд рдирд╛рд╣реА рдЕрд╕реЗ рд╡рдЪрди тАФ рдзрдбрд╛ 12 рдЪрд╛ рдЖрдврд╛рд╡рд╛ рддреЗ рдЕрдбрд╡реЗрд▓. рдЖрдгрд┐ downtime рдЪреЗ table рд╕реНрдкрд╖реНрдЯ рдХрд░рддреЗ рдХреА рдкрд╛рдЪрд╡рд╛ nine рдЗрддрдХрд╛ рдорд╣рд╛рдЧ рдХрд╛ рдЖрд╣реЗ: рддреЗ "рдЬрд╛рд╕реНрдд рдореЗрд╣рдирдд рдХрд░рд╛" рдирд╛рд╣реА, рддреЗ "loop рдордзреНрдпреЗ рдХреЛрдгрддрд╛рд╣реА рдорд╛рдгреВрд╕ рдирд╛рд╣реА" рдЖрд╣реЗ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

sre/design.py рдордзреНрдпреЗ: serial(avails) рдЧреБрдгрд╛рдХрд╛рд░ рдХрд░рддреЗ, parallel(a, n) 1 тИТ (1 тИТ a)тБ┐ рдкрд░рдд рджреЗрддреЗ, рдЖрдгрд┐ downtime(avail, period_h) рдПрдЦрд╛рджреНрдпрд╛ рдХрд╛рд▓рд╛рд╡рдзреАрдд рдкрд░рд╡рд╛рдирдЧреА рдЕрд╕рд▓реЗрд▓реА downtime рдЪреА рдорд┐рдирд┐рдЯреЗ рдкрд░рдд рджреЗрддреЗ. sre/demo.py рдордзреАрд▓ nines() рд╕рд╛рдЦрд│реА, рджреБрд╕рд░реА database рдкреНрд░рдд рдЖрдгрд┐ table рдХрд░рддреЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 sre/demo.py nines
python3 - <<'EOF'
import sys; sys.path.insert(0, "sre"); from design import serial, parallel, downtime
for n in (1, 2, 3):
    print(f"{n} app cop{'y' if n == 1 else 'ies'} at 99.5% тЖТ {parallel(0.995, n):.5%}")
for parts in (3, 10, 30):
    a = serial([0.999] * parts)
    print(f"{parts:>2} services in a row, each 99.9% тЖТ {a:.2%} ┬╖ {downtime(a, 24 * 28):6.0f} min down in 28 days")
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

nines рд╣реЗ рдЫрд╛рдкрддреЗ:

тФАтФА a request needs all three: gateway 99.99% ├Ч timetable app 99.95% ├Ч database 99.90% = 99.840%
   the chain is worse than its weakest part: 14.0 h a year of downtime allowed by the math
   two independent database copies: 1 тИТ (1 тИТ 0.999)┬▓ = 99.9999% тЖТ chain 99.940%
        99% тЖТ   87.60 h a year ┬╖  403.2 min in 28 days
      99.9% тЖТ    8.76 h a year ┬╖   40.3 min in 28 days
     99.95% тЖТ    4.38 h a year ┬╖   20.2 min in 28 days
     99.99% тЖТ    0.88 h a year ┬╖    4.0 min in 28 days
    99.999% тЖТ    0.09 h a year ┬╖    0.4 min in 28 days

рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:

1 app copy at 99.5% тЖТ 99.50000%
2 app copies at 99.5% тЖТ 99.99750%
3 app copies at 99.5% тЖТ 99.99999%
 3 services in a row, each 99.9% тЖТ 99.70% ┬╖    121 min down in 28 days
10 services in a row, each 99.9% тЖТ 99.00% ┬╖    401 min down in 28 days
30 services in a row, each 99.9% тЖТ 97.04% ┬╖   1192 min down in 28 days

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рд░рд╛рдВрдЧреЗрддреАрд▓ рддреАрди рдЪрд╛рдВрдЧрд▓реЗ рднрд╛рдЧ (99.84%) 99.9% SLO рдкреВрд░реНрдг рдХрд░реВ рд╢рдХрдд рдирд╛рд╣реАрдд тАФ code рдЪреА рдПрдХ рдУрд│ рд▓рд┐рд╣рд┐рдгреНрдпрд╛рдЖрдзреАрдЪ design рдЪреБрдХрд▓реЗрд▓реЗ рдЖрд╣реЗ. рджреБрд╕рд▒реНрдпрд╛, рд╕реНрд╡рддрдВрддреНрд░ database рдкреНрд░рддреАрдиреЗ рддреЗ рджреБрд░реБрд╕реНрдд рдЭрд╛рд▓реЗ (99.94%). 99.5% рдЪреНрдпрд╛ рджреЛрди рд╕реНрд╡рд╕реНрдд рдкреНрд░рддреА рдПрдХрд╛ рдорд╣рд╛рдЧ 99.9% рднрд╛рдЧрд╛рдкреЗрдХреНрд╖рд╛ рд╕рд░рд╕ рдард░рддрд╛рдд тАФ рдЬрд░ рддреНрдпрд╛ рдЦрд░реЛрдЦрд░ рд╕реНрд╡рддрдВрддреНрд░ рдЕрд╕рддреАрд▓. рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХреА рддреАрди nines рдЕрд╕рд▓реЗрд▓реНрдпрд╛ 30 services рдордзреВрди рдкрд╕рд░рдгрд╛рд░реА request рдорд╣рд┐рдиреНрдпрд╛рд▓рд╛ рд╕рд╛рдзрд╛рд░рдг 20 рддрд╛рд╕ рдмрдВрдж рдЕрд╕рддреЗ: рдореНрд╣рдгреВрдирдЪ рдЦреЛрд▓ call chains рдирд╛ timeouts, fallbacks рдЖрдгрд┐ рдХрдореА hard dependencies рд▓рд╛рдЧрддрд╛рдд.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

Request рдЪреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ hard dependency рдЪреА рдпрд╛рджреА рдХрд░рд╛, рддрд┐рдЪреНрдпрд╛ рдореЛрдЬрд▓реЗрд▓реНрдпрд╛ availability рд╕рд╣ (рддрд┐рдЪрд╛ SLA рдирд╛рд╣реА). рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ Prometheus рдордзреВрди, 28 рджрд┐рд╡рд╕рд╛рдВрддреАрд▓ database рд▓рд╛ рдХреЗрд▓реЗрд▓реНрдпрд╛ calls рдЪреЗ success ratio (metric рдЖрдгрд┐ label рдЪреА рдирд╛рд╡реЗ рддреБрдордЪреА):

curl -s http://prometheus:9090/api/v1/query --data-urlencode \
  'query=sum(increase(db_client_requests_total{outcome="success"}[28d])) / sum(increase(db_client_requests_total[28d]))' \
  | jq -r '.data.result[0].value[1]'

рдордЧ service repo рдордзреНрдпреЗ SLO рдЪреНрдпрд╛ рд╢реЗрдЬрд╛рд░реА рд╕рд╛рдЦрд│реА рд▓рд┐рд╣реВрди рдареЗрд╡рд╛:

slo: 99.9
hard_dependencies:        # measured over the last 28 days
  gateway: 99.99
  timetable-app: 99.95
  database: 99.9          # тЖТ add a replica in another zone with automatic failover
chain_ceiling: 99.84      # serial product тАФ below the SLO: must fix
soft_dependencies: [recommendations, photos]   # have fallbacks, not in the chain

рд╕реНрд╡рд╛рддрдВрддреНрд░реНрдп design рдХрд░рд╛рд╡реЗ рд▓рд╛рдЧрддреЗ: рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ zones рдордзреАрд▓ рдкреНрд░рддреА (рдзрдбрд╛ 07 рдЪрд╛ topology spread), рд╡реАрдЬ рдЖрдгрд┐ network рд╕рд╛рдареА рд╡реЗрдЧрд╡реЗрдЧрд│реЗ failure domains, рдЖрдгрд┐ рдЯрдкреНрдкреНрдпрд╛рдЯрдкреНрдкреНрдпрд╛рдиреЗ рдХреЗрд▓реЗрд▓реЗ config pushes, рдореНрд╣рдгрдЬреЗ рдПрдХ рд╡рд╛рдИрдЯ push рдПрдХрджрдо рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рддреАрдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪреВ рд╢рдХрдд рдирд╛рд╣реА.

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ рдЖрд╣реЗ: рддреБрдордЪреНрдпрд╛ service рдЪрд╛ SLO рдШреНрдпрд╛ рдЖрдгрд┐ рддрд┐рдЪреНрдпрд╛ hard dependencies рдЪреНрдпрд╛ рдореЛрдЬрд▓реЗрд▓реНрдпрд╛ availability рдЪрд╛ рдЧреБрдгрд╛рдХрд╛рд░ рдХрд░рд╛. рдЧреБрдгрд╛рдХрд╛рд░ SLO рдкреЗрдХреНрд╖рд╛ рдХрдореА рдЕрд╕реЗрд▓, рддрд░ рддреБрдореНрд╣рд╛рд▓рд╛ рддреБрдордЪрд╛ рдкреБрдврдЪрд╛ project рд╕рд╛рдкрдбрд▓рд╛ рдЖрд╣реЗ тАФ рдХрд┐рдВрд╡рд╛ рддреБрдордЪрд╛ SLO рдЪреБрдХреАрдЪрд╛ рдЖрд╣реЗ.

тПня╕П рдкреБрдвреЗ

рдЧрдгрд┐рддрд╛рдиреЗ рдЕрд╕реЗ рдЧреГрд╣реАрдд рдзрд░рд▓реЗ рдХреА рдорд╛рдЧрдгреА capacity рдордзреНрдпреЗ рдмрд╕рддреЗ. рдЗрдорд╛рд░рдд рд╕рд╛рдорд╛рд╡реВ рд╢рдХреЗрд▓ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдЖрд▓реЗ, рддрд░ рддреБрдореНрд╣реА рдиреАрдЯ рдЕрдкрдпрд╢реА рдХрд╕реЗ рд╣реЛрддрд╛?

git checkout lesson-10-overload

ЁЯФв Lesson 09 тАФ Reliability math: chains, copies and what each nine costs

ЁЯУН You are here: Lesson 09 of 12 ┬╖ Previous: lesson-08-incident-command ┬╖ Next: lesson-10-overload


ЁЯУж What's in this branch

Part 3 begins: designing for failure. Before building anything, do the arithmetic. Parts in a row (serial) multiply their availability down; independent copies (parallel) add nines. And each extra nine leaves ten times less downtime тАФ soon less than a person needs to react. serial, parallel and downtime in sre/design.py and nines() in sre/demo.py.

ЁЯзТ Explain like I'm 5

To get to the timetable, a pupil walks through three doors in a row: the gate, the hall door and the office door. ЁЯЪкЁЯЪкЁЯЪк If any door is stuck, the pupil cannot get in.

The gate works 99.99% of the time, the hall door 99.95%, the office door 99.9%. Together? You multiply: 99.84%. That is worse than even the worst door. Every door you add makes the trip less reliable.

Now the crew builds a second office door right next to the first. If one is stuck, you use the other. Both are stuck only if both are stuck at the same moment тАФ which is very rare (as long as they don't share the same lock!). The office becomes 99.9999%, and the whole trip becomes 99.94%.

ЁЯЧ║я╕П Diagram

flowchart LR
    u["ЁЯСйтАНЁЯОУ pupil"] --> g["gateway<br/>99.99%"] --> a["timetable app<br/>99.95%"] --> d["database<br/>99.9%"]
    d --> r1["serial: 99.84%<br/>14.0 h a year"]
    a --> d1["db copy 1<br/>99.9%"]
    a --> d2["db copy 2<br/>99.9%"]
    d1 & d2 --> r2["parallel: 99.9999%<br/>chain 99.94%"]

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/sre/lesson-diagrams.html#l09

тЭУ What

ЁЯдФ Why

Because SLOs (lesson 02) are promises, and this is how you check a promise is even possible before you make it. A 99.9% SLO on top of a chain that multiplies to 99.84% is a promise the design cannot keep тАФ lesson 12's review will block it. And the downtime table explains why the fifth nine is so expensive: it is not "work harder", it is "no human in the loop".

ЁЯФз How (in this repo)

In sre/design.py: serial(avails) multiplies, parallel(a, n) returns 1 тИТ (1 тИТ a)тБ┐, and downtime(avail, period_h) returns the allowed minutes of downtime in a period. nines() in sre/demo.py does the chain, the second database copy and the table.

ЁЯзк Try it

python3 sre/demo.py nines
python3 - <<'EOF'
import sys; sys.path.insert(0, "sre"); from design import serial, parallel, downtime
for n in (1, 2, 3):
    print(f"{n} app cop{'y' if n == 1 else 'ies'} at 99.5% тЖТ {parallel(0.995, n):.5%}")
for parts in (3, 10, 30):
    a = serial([0.999] * parts)
    print(f"{parts:>2} services in a row, each 99.9% тЖТ {a:.2%} ┬╖ {downtime(a, 24 * 28):6.0f} min down in 28 days")
EOF

тЬЕ Verify тАФ what you should see

nines prints:

тФАтФА a request needs all three: gateway 99.99% ├Ч timetable app 99.95% ├Ч database 99.90% = 99.840%
   the chain is worse than its weakest part: 14.0 h a year of downtime allowed by the math
   two independent database copies: 1 тИТ (1 тИТ 0.999)┬▓ = 99.9999% тЖТ chain 99.940%
        99% тЖТ   87.60 h a year ┬╖  403.2 min in 28 days
      99.9% тЖТ    8.76 h a year ┬╖   40.3 min in 28 days
     99.95% тЖТ    4.38 h a year ┬╖   20.2 min in 28 days
     99.99% тЖТ    0.88 h a year ┬╖    4.0 min in 28 days
    99.999% тЖТ    0.09 h a year ┬╖    0.4 min in 28 days

Your snippet prints:

1 app copy at 99.5% тЖТ 99.50000%
2 app copies at 99.5% тЖТ 99.99750%
3 app copies at 99.5% тЖТ 99.99999%
 3 services in a row, each 99.9% тЖТ 99.70% ┬╖    121 min down in 28 days
10 services in a row, each 99.9% тЖТ 99.00% ┬╖    401 min down in 28 days
30 services in a row, each 99.9% тЖТ 97.04% ┬╖   1192 min down in 28 days

ЁЯПБ What you just proved

Three good parts in a row (99.84%) cannot meet a 99.9% SLO тАФ the design is wrong before a line of code is written. A second, independent database copy fixed it (99.94%). Two cheap 99.5% copies beat one expensive 99.9% part тАФ if they are really independent. And a request that fans out through 30 services at three nines each is down about 20 hours a month: that is why deep call chains need timeouts, fallbacks and fewer hard dependencies.

тЪая╕П Common mistakes

ЁЯПн In production

List every hard dependency of a request, with its measured availability (not its SLA). On a real account тАФ from Prometheus, the success ratio of calls to the database over 28 days (the metric and label names are yours):

curl -s http://prometheus:9090/api/v1/query --data-urlencode \
  'query=sum(increase(db_client_requests_total{outcome="success"}[28d])) / sum(increase(db_client_requests_total[28d]))' \
  | jq -r '.data.result[0].value[1]'

Then write the chain down next to the SLO, in the service repo:

slo: 99.9
hard_dependencies:        # measured over the last 28 days
  gateway: 99.99
  timetable-app: 99.95
  database: 99.9          # тЖТ add a replica in another zone with automatic failover
chain_ceiling: 99.84      # serial product тАФ below the SLO: must fix
soft_dependencies: [recommendations, photos]   # have fallbacks, not in the chain

Independence is designed: copies in different zones (lesson 07's topology spread), different failure domains for power and network, and staged config pushes so one bad push cannot reach every copy at once.

ЁЯПн Why this matters in production: take your service's SLO and multiply the measured availability of its hard dependencies. If the product is below the SLO, you have found your next project тАФ or your SLO is wrong.

тПня╕П Next

The math assumed demand fits the capacity. When more arrives than the building can hold, how do you fail well?

git checkout lesson-10-overload
тЖР Previousincident commandNext тЖТoverload

This page is the lesson's README from the lesson-09-reliability-math branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.