Wydajność aplikacji webowej często rozbija się nie o sam kod, ale o liczbę niepotrzebnych przejść do backendu. Varnish Cache jest jednym z najskuteczniejszych narzędzi, gdy trzeba odciążyć aplikację, przyspieszyć odpowiedź i zapanować nad ruchem HTTP bez przebudowy całej architektury. Dokumentacja Varnish podaje przyspieszenie rzędu 300-1000x w dobrze dobranych scenariuszach, ale ja traktuję to jako efekt zależny od polityki cache, a nie cudowny standard. W tym tekście pokazuję, jak to działa, co warto cache’ować, jak odświeżać treści i kiedy to rozwiązanie ma sens w backendzie oraz DevOpsie.
Varnish daje największy zysk tam, gdzie ruch jest powtarzalny, a zasady cache są jasno zdefiniowane
- Działa jako reverse proxy przed aplikacją i przechwytuje żądania HTTP, zanim trafią do backendu.
- Najlepiej sprawdza się przy publicznych GET i HEAD, statycznych zasobach oraz stronach o przewidywalnej zmianie.
- TTL, grace, purge i ban to cztery mechanizmy, które realnie decydują o świeżości treści.
- Odpowiedzi z cookie, autoryzacją lub personalizacją wymagają ostrożności, bo łatwo zepsuć hit ratio.
- W praktyce ważniejsze od samego wdrożenia są monitoring, logika unieważniania i kontrola backendu.
Czym jest Varnish i gdzie pasuje w architekturze
Ja zwykle opisuję Varnish jako szybki pośrednik między klientem a aplikacją. Stoi przed backendem, odbiera żądanie HTTP, sprawdza, czy ma gotową odpowiedź w cache, a jeśli nie, pobiera ją z originu i może zachować na przyszłość.
To ważne rozróżnienie: nie jest zwykłym „przyspieszaczem”. Jego wartość polega na tym, że potrafi odciążyć aplikację, bazę danych i warstwę renderowania w miejscach, gdzie odpowiedź jest powtarzalna. W praktyce najlepiej działa tam, gdzie dużo ruchu dotyczy tych samych zasobów, a backend jest droższy niż sam cache.
W architekturze produkcyjnej Varnish często ląduje przed aplikacją, ale może też współpracować z CDN. CDN bierze na siebie globalną dystrybucję i bliskość geograficzną, a Varnish - bardziej szczegółową logikę cache i kontrolę nad unieważnianiem. To prowadzi wprost do pytania, w jaki sposób podejmuje decyzję o tym, co może przejść przez cache, a co powinno wrócić prosto do źródła.
Jak działa decyzja o cache w praktyce
W praktyce cały mechanizm opiera się na kilku stanach: hit, miss, grace i pass. Przy hit odpowiedź jest już w pamięci i wychodzi natychmiast. Przy miss Varnish musi uderzyć do backendu. Grace pozwala przez krótki czas serwować obiekt, który formalnie się zestarzał, ale nadal jest lepszy niż czekanie na origin. Pass oznacza, że danego żądania nie opłaca się cache’ować.
| Stan | Co to znaczy | Skutek dla użytkownika |
|---|---|---|
| Hit | Odpowiedź już istnieje w cache | Najkrótszy czas odpowiedzi |
| Miss | Trzeba pobrać dane z backendu | Pierwsze żądanie jest wolniejsze |
| Grace | Treść jest lekko przeterminowana, ale nadal może zostać podana | Szybka odpowiedź mimo chwilowego opóźnienia originu |
| Pass | Varnish świadomie omija cache | Każde żądanie idzie do aplikacji |
Najważniejsza jest jednak nie sama definicja stanu, tylko sposób zbudowania klucza cache. Jeśli w hash uwzględnisz zbyt mało danych, użytkownik może dostać cudzą odpowiedź. Jeśli uwzględnisz zbyt dużo, hit ratio spadnie i cały sens optymalizacji się rozmyje. Właśnie dlatego VCL nie jest dodatkiem, tylko częścią decyzji architektonicznej. Z tego wynika następny praktyczny krok: trzeba bardzo jasno oddzielić treści bezpieczne do buforowania od tych, które cache’ować należy ostrożnie albo wcale.

Co warto cache’ować, a czego lepiej nie ruszać
W większości projektów najlepszym kandydatem są publiczne odpowiedzi GET i HEAD: strony artykułów, listingi, karty produktów bez personalizacji oraz statyczne pliki CSS, JS i obrazy. To są klasyczne przypadki, w których cache daje realny zysk bez komplikowania logiki biznesowej.
| Kategoria | Ocena | Dlaczego |
|---|---|---|
| Statyczne assety | Bardzo dobry kandydat | Rzadko się zmieniają i nie zależą od użytkownika |
| Publiczne artykuły i landing pages | Dobry kandydat | Duża powtarzalność ruchu, łatwo kontrolować TTL |
| Strony zalogowanych użytkowników | Ostrożnie | Treść bywa zależna od sesji, koszyka, ról i preferencji |
| Odpowiedzi z Set-Cookie | Zazwyczaj nie cache’ować bez filtracji | Cookie często oznacza personalizację albo stan sesji |
| Webhooki, POST, niestandardowe metody | Zwykle nie cache’ować | To nie jest ruch, który przynosi korzyść z buforowania |
Dokumentacja Varnish przypomina, że odpowiedzi z nagłówkiem Set-Cookie nie są domyślnie cache’owane, i to jest rozsądna domyślna ostrożność. Jeśli jednak backend dokleja cookie techniczne albo trackingowe, można je wyczyścić w VCL albo z pomocą vmod cookie, zamiast wyrzucać całe cache. To rozwiązanie bywa dużo bardziej opłacalne niż rezygnacja z buforowania na całej ścieżce.
Ja w praktyce zaczynam od prostego filtra: cache tylko to, co jest publiczne, przewidywalne i nie zależy od stanu zalogowania. Dopiero potem dokładam wyjątki, jeśli analiza ruchu pokazuje, że naprawdę warto. To płynnie prowadzi do pytania o świeżość danych, bo samo cache’owanie bez dobrego unieważniania szybko kończy się starymi treściami albo chaosem operacyjnym.
Jak odświeżać treści bez psucia wydajności
Najczęściej używam czterech mechanizmów: TTL, grace, purge i ban. TTL określa, jak długo obiekt jest świeży. Grace pozwala podać użytkownikowi chwilowo starszą treść, gdy backend nie nadąża lub ma problem. Purge usuwa obiekt z cache od razu. Ban nie tyle usuwa, co oznacza określone obiekty jako nieważne, dzięki czemu Varnish przestaje je serwować przy kolejnych trafieniach.
| Mechanizm | Kiedy go użyć | Plus | Ryzyko |
|---|---|---|---|
| TTL | Gdy treść ma przewidywalny czas życia | Prosty model świeżości | Zbyt krótki TTL obniża hit ratio |
| Grace | Gdy backend bywa wolny lub niestabilny | Użytkownik dostaje odpowiedź mimo problemów | Treść może być chwilowo starsza |
| Purge | Gdy konkretny zasób zmienił się natychmiast | Szybka reakcja na zmianę | Łatwo przesadzić i wyczyścić za dużo |
| Ban | Gdy trzeba unieważnić grupę obiektów po metadanych | Precyzja i elastyczność | Zbyt wiele banów potrafi obciążyć CPU |
W architekturach contentowych sensownie działa model „krótki TTL + umiarkowany grace”. Na przykład przy stronach redakcyjnych można pozwolić sobie na kilkadziesiąt sekund albo kilka minut zapasu, zamiast blokować użytkownika na backend. W DevOpsie to ważne, bo grace działa trochę jak amortyzator: nie naprawia źródła problemu, ale ogranicza jego skutki dla ruchu produkcyjnego.
sub vcl_backend_response {
set beresp.ttl = 5m;
set beresp.grace = 2m;
set beresp.keep = 10m;
}Ten prosty wzorzec daje dobry punkt startowy, ale nie powinien być kopiowany bez refleksji. Jeśli treść jest krytyczna czasowo, trzeba skrócić grace. Jeśli backend jest drogi i stabilny, można pozwolić sobie na więcej. Właśnie tu Varnish przestaje być tylko cache’em, a zaczyna być narzędziem polityki świeżości. Z tego miejsca warto już porównać go z innymi elementami stosu, bo wybór między Varnishem, CDN-em i Nginxem nie zawsze jest oczywisty.
Kiedy Varnish ma sens bardziej niż CDN albo Nginx
Najprościej mówiąc: CDN daje zasięg geograficzny, Nginx daje prostotę, a Varnish daje kontrolę nad cache’owaniem HTTP. To nie są produkty konkurujące jeden do jednego, ale w praktyce często stają przed tym samym pytaniem: gdzie zatrzymać żądanie, żeby backend nie płacił za każdą odpowiedź.
| Kryterium | Varnish | CDN | Nginx cache |
|---|---|---|---|
| Kontrola nad polityką cache | Bardzo wysoka | Zależy od dostawcy | Umiarkowana |
| Personalizacja reguł | Świetna dzięki VCL | Ograniczona lub kosztowna | Prostsza, ale mniej elastyczna |
| Zasięg globalny | Nie jest jego główną rolą | Tak | Nie |
| Łatwość uruchomienia | Średnia | Średnia | Wysoka |
| Najlepsze zastosowanie | Dynamiczne serwisy z potrzebą precyzyjnego cache | Static heavy, global traffic, edge delivery | Mniejsze lub prostsze środowiska |
Ja najczęściej widzę dwa sensowne scenariusze: CDN przed Varnishem albo Varnish bezpośrednio przed aplikacją. Pierwszy wariant ma sens, gdy masz ruch z różnych regionów i chcesz odciąć jak najwięcej zapytań jeszcze na brzegu sieci. Drugi sprawdza się, gdy problemem jest przede wszystkim przeciążony origin, a zasięg geograficzny nie jest najważniejszy. Z tego wynika ostatnia część: nawet najlepsza architektura nie zadziała, jeśli wdrożenie i monitoring będą traktowane po macoszemu.
Jak wdrożyć to bez niespodzianek na produkcji
W praktyce wdrażam Varnish etapami. Najpierw obejmuję nim tylko publiczne GET i HEAD, potem dopiero rozszerzam reguły o bardziej złożone przypadki. To zmniejsza ryzyko, że jedna źle ustawiona reguła utnie logowanie, koszyk albo panel administracyjny.
- Ustal jasną politykę cache dla każdego typu odpowiedzi, zanim ruszysz z produkcją.
- Normalizuj nagłówki i cookies tak, żeby różnice naprawdę istotne biznesowo trafiały do klucza cache.
- Zabezpiecz PURGE i BAN ACL-em albo osobnym kanałem administracyjnym.
- Monitoruj hit ratio, liczbę backend fetchy, p95 latency i liczbę 5xx po stronie originu.
- Sprawdzaj, czy ban list nie rośnie bez kontroli i czy backend wciąż odpowiada szybko po wygaśnięciu cache.
W codziennej pracy najbardziej przydają mi się varnishstat i varnishlog, bo pokazują, czy problem leży w cache, backendzie czy w samej polityce żądań. Warto też testować zachowanie w czasie awarii originu: wtedy od razu widać, czy grace faktycznie ratuje użytkownika, czy jest tylko ładnym zapisem w konfiguracji. To naturalnie prowadzi do ostatniego pytania: co najczęściej psuje efekt, nawet gdy narzędzie zostało postawione poprawnie.
Co najczęściej zabiera efekt cache’owania
Największe straty nie wynikają z samego Varnisha, tylko z błędnej polityki. Jeśli cache’ujesz odpowiedzi zależne od sesji, hit ratio będzie niskie i pojawią się trudne do diagnozowania błędy. Jeśli TTL jest zbyt krótki, backend dostaje prawie tyle samo ruchu co wcześniej. Jeśli przy każdej zmianie treści czyścisz cały cache, zamieniasz accelerator w generator zbędnych fetchy.
Ja patrzę na tę technologię dość pragmatycznie: Varnish daje świetny zwrot z inwestycji tam, gdzie ruch jest powtarzalny, a odpowiedzi da się jasno sklasyfikować. Nie zastępuje dobrego backendu, nie naprawia chaosu w nagłówkach i nie rozwiązuje problemu niekontrolowanej personalizacji. Ale jeśli ustawisz go świadomie, staje się jedną z tych warstw, które realnie obniżają koszty, stabilizują aplikację i pozwalają zespołowi skupić się na tym, co naprawdę wymaga logiki biznesowej, a nie powtarzalnego serwowania tych samych odpowiedzi.
