Modul 15 — Senior úroveň: architektura a leadership

69. Návrh škálovatelné infrastruktury pro produkční systémy

Jak navrhnout infrastrukturu, která zvládne růst zátěže — horizontální škálování, load balancing, cachování, škálování databází a role kontejnerové orchestrace a cloudu.

Odhadovaná délka studia: 60 minut · Stav: nehotovo

Technologie: Architektura infrastruktury Cloud computing Databáze (PostgreSQL/MySQL) Kubernetes

Úvod a kontext

Dosavadní moduly probraly jednotlivé stavební bloky — servery,
databáze, kontejnery, Kubernetes, cloud. Tato lekce, první z bloku
"senior úroveň", je o tom, jak tyto bloky poskládat do jednoho
konzistentního návrhu infrastruktury, která zvládne růst z desítek
na statisíce uživatelů, aniž by se musela každý půlrok kompletně
přestavět. Jde o typickou zodpovědnost seniorního DevOps/SRE
inženýra nebo architekta.

Teorie

Vertikální vs. horizontální škálování

Vertikální škálování (scale up) znamená přidat výkonnějšímu
serveru více CPU/RAM/disku. Je jednoduché (žádná změna architektury
aplikace), ale má tvrdý strop — existuje maximální velikost stroje,
kterou lze koupit či pronajmout, a je to single point of failure
(padne-li ten jeden velký server, padne vše).

Horizontální škálování (scale out) znamená přidat další,
stejně velké instance aplikace a rozdělit mezi ně zátěž. Vyžaduje,
aby aplikace byla bezstavová (stateless) — každý požadavek musí
jít obsloužit kterýmkoliv instancí, bez závislosti na tom, co si
"pamatuje" konkrétní server (session data patří do sdíleného úložiště
typu Redis, ne do paměti procesu). Horizontální škálování je pružnější
a odolnější, ale vyžaduje více architektonické disciplíny předem.

Load balancing jako základní stavební kámen

Horizontální škálování potřebuje něco, co rozděluje příchozí
požadavky mezi instance — load balancer (viz Nginx jako reverzní
proxy, modul 5, nebo Kubernetes Service, modul 8). V cloudu tuto roli
běžně přebírá spravovaný load balancer (AWS ALB/NLB, viz modul 11),
který navíc umí automaticky vyřadit nezdravé instance na základě
health checků (modul 8).

Cachování

Cache snižuje zátěž na pomalejší vrstvy systému (typicky databázi)
tím, že často čtená data drží blíž a rychleji dostupná:

  • Cache na úrovni aplikace/in-memory (Redis, Memcached) — pro
    výsledky drahých dotazů nebo výpočtů.
  • CDN (Content Delivery Network) — cachuje statický obsah
    (obrázky, JS, CSS) na serverech geograficky blízko uživateli, čímž
    snižuje latenci a zátěž na origin server.
  • HTTP cache hlavičky — umožňují prohlížeči nebo proxy cachovat
    odpověď bez dotazu na server vůbec.

Cachování přináší vlastní komplexitu — tzv. invalidace cache
("cache invalidation" je pověstně jeden ze dvou "opravdu těžkých
problémů v informatice"): když se podkladová data změní, je potřeba
zajistit, že cache neukazuje zastaralá data déle, než je přijatelné.

Škálování databáze

Databáze je nejčastěji nejtěžší částí architektury na škálování,
protože (na rozdíl od bezstavové aplikace) drží stav:

  • Read repliky (viz modul 6) odlehčí čtecí zátěž tím, že se čtení
    rozloží na více kopií dat, zatímco zápisy jdou stále na jeden
    primární uzel.
  • Connection pooling (viz incident v modulu 14) zabrání tomu, aby
    velké množství instancí aplikace vyčerpalo limit současných
    připojení k databázi.
  • Sharding (dělení dat podle klíče, např. podle ID zákazníka, na
    více nezávislých databázových instancí) řeší škálování zápisů, ale
    je architektonicky nákladné — zavádí ho až tým, který skutečně
    narazil na limit jedné instance, ne preventivně od začátku.
  • Cachování před databází (viz výše) je často nejlevnější první
    krok, než se sáhne po replikaci nebo shardingu.

Role kontejnerů a orchestrace

Kontejnery a Kubernetes (moduly 7–8) usnadňují horizontální
škálování tím, že standardizují, jak se aplikace balí a spouští, a
HorizontalPodAutoscaler (modul 8) umí počet instancí (Podů)
automaticky přizpůsobovat aktuální zátěži bez ručního zásahu.
V cloudu (modul 11) navíc autoscaling skupiny umí přidávat i celé
nové výpočetní uzly, na kterých Pody běží, takže se škáluje jak
aplikace, tak podkladová infrastruktura.

Návrhový princip: škáluj podle skutečného úzkého hrdla

Časná chyba je předčasně optimalizovat všechno najednou. Seniorní
přístup je změřit (metriky z modulu 12), najít skutečné úzké hrdlo
(bottleneck) — často je to databáze, ne aplikační vrstva — a řešit
právě to, místo plošného "přidáme víc serverů všude". Škálovací
opatření mají cenu (peníze, komplexita, provozní zátěž), takže se
zavádí, až když je reálně potřeba, podloženo daty, ne intuicí.

Praktický příklad

Zjednodušený diagram typické škálovatelné produkční architektury
webové aplikace (popsáno textově, odshora dolů podle toku
požadavku):

Uživatel
  │
  ▼
CDN (statický obsah: JS, CSS, obrázky)
  │
  ▼
Load Balancer (AWS ALB / Nginx)
  │
  ├──► App instance 1 (Kubernetes Pod)
  ├──► App instance 2 (Kubernetes Pod)
  └──► App instance N (Kubernetes Pod, škáluje HPA podle CPU/latence)
         │
         ├──► Redis cache (často čtená data, session store)
         │
         └──► PostgreSQL primární (zápisy)
                │
                ├──► Read replika 1 (čtení reportů)
                └──► Read replika 2 (čtení dashboardu)

Odpovídající zjednodušený HorizontalPodAutoscaler (viz modul 8),
který zajišťuje, že se počet App instancí přizpůsobuje zátěži:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: app
  minReplicas: 3
  maxReplicas: 30
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 65

Shrnutí

Škálovatelná infrastruktura kombinuje horizontální škálování
bezstavových aplikačních instancí (podpořené load balancerem a
kontejnerovou orchestrací), cachování na více úrovních (in-memory,
CDN) a strategie pro škálování databáze (read repliky, connection
pooling, v krajním případě sharding). Klíčový návrhový princip je
škálovat podle skutečně změřeného úzkého hrdla, ne plošně a
preventivně — komplexita a náklady škálovacích opatření se mají
zavádět, až když jsou opodstatněné daty.

Kontrolní otázky

  1. Proč musí být aplikace bezstavová, aby šla efektivně horizontálně
    škálovat, a kam se má přesunout stav (např. session), který by
    jinak žil v paměti jednoho serveru?
  2. Jaký je rozdíl mezi read replikami a shardingem jako strategiemi
    škálování databáze a proč se sharding zavádí jako poslední
    možnost?
  3. Co znamená princip "škáluj podle skutečného úzkého hrdla" a proč
    je bezpečnější než plošně přidávat kapacitu všude?
  4. Mini cvičení: v diagramu výše navrhněte, kam byste přidali
    dodatečnou cache vrstvu, kdyby metriky ukázaly, že hlavní úzké
    hrdlo je opakované čtení stejných dat z read replik.

Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.