Modul 5 — Webové servery a reverzní proxy
24. Ladění výkonu webového serveru a cachování
Gzip/brotli komprese, HTTP cachovací hlavičky, cachování na úrovni Nginx a základní zátěžové testování.
Úvod a kontext
Funkční webový server (předchozí tři lekce) je první krok — druhý je
udělat ho rychlý i pod zátěží. Dva nejúčinnější nástroje, které má
provozní inženýr k dispozici bez zásahu do samotné aplikace, jsou
komprese přenášených dat a cachování (ukládání odpovědí do
mezipaměti, aby se opakované požadavky nemusely znovu draze počítat).
Tato lekce shrnuje obě techniky na úrovni Nginx a ukazuje základní způsob,
jak zjistit, jestli změna výkon skutečně zlepšila.
Teorie
Proč záleží na výkonu webového serveru
Pomalá odpověď serveru znamená déle čekajícího uživatele, vyšší zátěž
serveru při stejném počtu požadavků a horší chování pod špičkovou zátěží
(víc souběžně otevřených spojení, protože každé trvá déle). Dvě hlavní
páky, které nevyžadují zásah do aplikace samotné:
- méně dat na drátě — komprese,
- méně výpočtů/dotazů na backend — cachování.
Komprese (gzip, brotli)
HTTP odpovědi (zejména textové — HTML, CSS, JavaScript, JSON) lze před
odesláním komprimovat; prohlížeč je na straně klienta automaticky
rozbalí. Textový obsah se kompresí typicky zmenší o 60–80 %.
http {
gzip on;
gzip_types text/plain text/css application/javascript application/json;
gzip_min_length 1024;
gzip_comp_level 5;
}
gzip_types— komprimují se jen vyjmenované typy obsahu; obrázky
(JPEG, PNG) a videa jsou už komprimované samy o sobě, další komprese by
jen plýtvala CPU bez přínosu,gzip_min_length 1024— nemá smysl komprimovat velmi malé odpovědi,
režie komprese by převážila úsporu,gzip_comp_level— úroveň komprese 1–9; vyšší = menší výstup, ale víc
CPU. Hodnota 5–6 je obvykle rozumný kompromis.
Modernější a účinnější alternativou je brotli (vyžaduje doplňkový
modul, není součástí standardní instalace Nginx) — dosahuje o něco menší
výsledné velikosti než gzip při srovnatelné rychlosti.
HTTP cachovací hlavičky
Server může prohlížeči (nebo mezilehlé cachi) říct, jak dlouho si má
odpověď uložit, aby ji příště nemusel stahovat znovu:
location /static/ {
expires 30d;
add_header Cache-Control "public, immutable";
}
expires 30d— nastaví hlavičkuExpiresaCache-Control: max-age=
na 30 dní; prohlížeč po tuto dobu soubor vůbec znovu nestáhne,immutable— signalizuje, že se obsah souboru na dané URL nikdy
nezmění (typické pro statické soubory se "fingerprintem" v názvu, např.
app.a3f21c.js— když se obsah změní, změní se i název souboru).
Pro dynamický obsah, který se často mění, je naopak vhodné cachování
explicitně zakázat:
location /api/ {
add_header Cache-Control "no-store";
}
no-store říká prohlížeči i mezilehlým cachím, ať odpověď vůbec
neukládají — vhodné pro citlivá nebo často se měnící data.
Cachování na úrovni Nginx (proxy cache)
Nginx umí cachovat i odpovědi z backendu, na který funguje jako reverzní
proxy (viz minulá lekce) — opakované požadavky na stejnou URL pak vůbec
nedojdou k aplikaci:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=moje_cache:10m max_size=1g;
server {
location / {
proxy_pass http://127.0.0.1:8000;
proxy_cache moje_cache;
proxy_cache_valid 200 10m;
proxy_cache_valid 404 1m;
add_header X-Cache-Status $upstream_cache_status;
}
}
proxy_cache_path— kam a jak velkou cache ukládat na disk
(keys_zone=moje_cache:10mvyhrazuje 10 MB paměti pro metadata cache,
max_size=1gje limit velikosti na disku),proxy_cache_valid 200 10m— úspěšné odpovědi (200) se cachují na 10
minut,404jen na 1 minutu (aby se chybějící stránka rychle "opravila"
poté, co ji administrátor doplní),X-Cache-Status— přidá do odpovědi hlavičku ukazující, jestli odpověď
přišla z cache (HIT) nebo z backendu (MISS) — nejrychlejší způsob,
jak si přímo v prohlížeči nebo přescurl -Iověřit, že cachování
funguje.
Proxy cache je mocný nástroj, ale je potřeba ji používat opatrně u
obsahu specifického pro konkrétního uživatele (přihlášený uživatel,
osobní data) — bez správného rozlišení klíče cache (proxy_cache_key)
hrozí, že jeden uživatel uvidí cachovanou odpověď určenou jinému.
Základní zátěžové testování
Než a po jakékoliv úpravě výkonu je vhodné změnu změřit, ne jen
"odhadnout, že to bude rychlejší". Jednoduchý nástroj ab (Apache
Bench, součást balíčku apache2-utils, funguje i pro testování Nginx):
ab -n 1000 -c 50 http://example.cz/
-n 1000— celkem 1000 požadavků,-c 50— 50 souběžných spojení najednou.
Výstup obsahuje mimo jiné Requests per second (kolik požadavků server
zvládne za sekundu) a Time per request (průměrná doba odpovědi) — tato
dvě čísla se porovnávají před a po úpravě konfigurace, aby bylo vidět,
jestli změna skutečně pomohla.
Praktický příklad
Kombinovaná konfigurace se statickým obsahem s dlouhou platností v cachi,
kompresí a proxy cache pro dynamický obsah z backendu:
http {
gzip on;
gzip_types text/plain text/css application/javascript application/json;
gzip_min_length 1024;
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=kurzy_cache:10m max_size=500m;
server {
listen 80;
server_name kurzy.example.cz;
location /static/ {
alias /home/petr/ai/tutor/staticfiles/;
expires 30d;
add_header Cache-Control "public, immutable";
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_cache kurzy_cache;
proxy_cache_valid 200 5m;
add_header X-Cache-Status $upstream_cache_status;
}
}
}
Ověření, že proxy cache funguje, dvěma po sobě jdoucími požadavky:
curl -sI http://kurzy.example.cz/ | grep X-Cache-Status # MISS (první požadavek)
curl -sI http://kurzy.example.cz/ | grep X-Cache-Status # HIT (druhý požadavek, z cache)
Porovnání výkonu s cachí a bez ní (pro test dočasně vypnuté proxy_cache):
ab -n 500 -c 20 http://kurzy.example.cz/
Shrnutí
Komprese (gzip) snižuje objem přenášených dat, dlouhé cachovací hlavičky
(expires, Cache-Control) šetří opakované stahování na straně klienta a
proxy cache na úrovni Nginx šetří výpočetní zátěž backendu tím, že
opakované požadavky vůbec nedojdou k aplikaci. Hlavička
X-Cache-Status (HIT/MISS) je nejrychlejší způsob ověření, že
cachování funguje, a nástroj ab umožňuje změnu výkonu skutečně změřit,
místo aby se jen odhadovala.
Kontrolní otázky
- Proč nemá smysl komprimovat obrázky ve formátu JPEG stejným způsobem
jako HTML nebo CSS? - K čemu slouží hlavička
Cache-Control: no-storea kdy byste ji
použili místo dlouhé platnosti (expires 30d)? - Co znamená hlavička
X-Cache-Status: HITa jak byste ji použili k
ověření, že proxy cache skutečně funguje? - Proč je nebezpečné zapnout
proxy_cachebez rozmyslu pro odpovědi
obsahující data specifická pro přihlášeného uživatele?
Lekce na sebe nejsou zamčené — libovolnou lekci můžete otevřít i označit jako hotovou v jakémkoliv pořadí.