Indeks dziennikaDockup / notatka terenowa
Note / unexpected-egress-charges

Nieoczekiwane opłaty za egress: skąd biorą się rachunki za bandwidth

Nieoczekiwane opłaty za egress zwykle wynikają z czterech nawyków: serwowania mediów z aplikacji, braku nagłówków cache, zbyt gadatliwych API i ruchu między regionami. Znajdź źródło problemu i obniż rachunek bez zmiany dostawcy.

Rachunek przychodzi i jest cztery razy wyższy, niż zakładałeś. Pozycja dotycząca compute mniej więcej odpowiada budżetowi. Inaczej wygląda egress — bajty opuszczające twoją infrastrukturę — i istnieje spora szansa, że do tej pory ani razu się nad nim nie zastanawiałeś.

Nieoczekiwane opłaty za egress to najczęstsza niespodzianka na rachunku za hosting aplikacji. Powód jest strukturalny: w procesie developmentu nic nie mierzy liczby przesyłanych bajtów. Twój laptop nie pobiera za nie opłat. Na stagingu nie ma użytkowników. Po raz pierwszy bandwidth staje się widoczny dopiero na fakturze, a wtedy na wdrożenie jest już nawyk, który spowodował problem.

Oto skąd naprawdę się bierze — w kolejności odpowiadającej częstotliwości występowania tych przyczyn.

1. Serwowanie mediów z aplikacji

Ten przypadek zdecydowanie przewyższa pozostałe i niemal zawsze jest przypadkowy.

Umieszczasz wideo w /public, żeby coś zademonstrować. Działa, więc zostaje. Teraz przy każdym wyświetleniu strony ten plik jest przesyłany z twojego kontenera. Jedno wideo o rozmiarze 40 MB na stronie odwiedzanej przez tysiąc osób miesięcznie to 40 GB — z pliku, który miał być tylko tymczasowym zastępstwem.

To samo dotyczy obrazów produktów, plików PDF, uploadów użytkowników i fontów. Gdy je dodajesz, żaden z tych elementów nie wydaje się decyzją dotyczącą infrastruktury.

Rozwiązanie nie wymaga sprytnych sztuczek: statyczne media powinny znajdować się w object storage za CDN-em, a nie w filesystemie aplikacji. Aplikacja powinna serwować HTML i JSON. Gdy zaczyna dostarczać każdemu użytkownikowi obraz hero o rozmiarze 4 MB, wykonuje pracę CDN-u, nie korzystając z żadnych jego zalet ekonomicznych.

2. Brak nagłówków cache

Jeśli twoje odpowiedzi nie zawierają nagłówków cache, każdy użytkownik pobiera każdy asset przy każdym ładowaniu strony. Powracający użytkownicy pobierają wszystko ponownie. Crawler robi to dziesiątki razy dziennie.

# Fingerprinted build assets never change — cache them for a year
Cache-Control: public, max-age=31536000, immutable

# HTML changes — revalidate but allow a short window
Cache-Control: public, max-age=0, must-revalidate

# Anything user-specific
Cache-Control: private, no-store

To jedna zmiana w każdym typie odpowiedzi, która regularnie eliminuje większość rachunku za bandwidth, ponieważ usuwany ruch jest czystym powtórzeniem.

3. API zwracające więcej danych, niż wykorzystuje klient

Endpoint listy, który zwraca pełne obiekty, mimo że UI wyświetla trzy pola, wysyła tę nadmiarową różnicę przy każdym żądaniu — bez końca. Nie widać tego w profilowaniu, bo wszystko działa szybko — odpowiedź jest po prostu duża.

Na dwóch najbardziej obciążonych endpointach sprawdź:

  • Czy kompresja jest włączona? Content-Encoding: gzip lub br w JSON-ie zwykle zmniejsza rozmiar o 70–80%. To jedna linia w middleware, a często jej brakuje.
  • Czy wysyłasz pola, których nikt nie odczytuje? Serializowanie całego wiersza, bo ORM to ułatwia, jest domyślnym zachowaniem w większości codebase’ów.

Klient wykonujący polling pogarsza oba problemy proporcjonalnie do liczby odpytań na minutę.

4. Ruch między regionami i usługami

Jeśli aplikacja działa w jednym regionie, a baza danych znajduje się w innym, każdy wynik zapytania przekracza płatną granicę. Łatwo o to przez przypadek — najpierw tworzysz bazę danych, wybierasz region bez większego namysłu, a kilka tygodni później umieszczasz aplikację gdzie indziej.

Ruch między własnymi usługami również może być obciążony opłatą za egress, jeśli opuszcza prywatną sieć, a następnie wraca przez publiczny hostname. Dwie usługi w tym samym workspace, komunikujące się za pośrednictwem publicznych URL-i, płacą dwa razy za rozmowę, która w ogóle nie musiała opuszczać sieci.

W Dockup ten konkretny błąd trudno popełnić, ponieważ usługi odwołują się do siebie za pomocą nazw wewnętrznych. Jedna usługa łączy się z main-db.internal:5432, a z inną za pośrednictwem jej aliasu <slug>.internal — ruch pozostający wewnątrz sieci workspace nie przechodzi przez publiczny listener. Dlatego baza danych domyślnie nie ma publicznego hostname’u: nie da się przypadkowo skierować przez niego ruchu.

Znajdź źródło problemu zamiast zgadywać

Zgadywanie, która z czterech przyczyn odpowiada za problem, marnuje cały cykl rozliczeniowy. Zamiast tego wykonaj pomiary:

Czytaj access log według liczby bajtów, a nie żądań. Posortuj najczęściej zwracane odpowiedzi według łącznej liczby przesłanych bajtów, a nie liczby żądań. Endpoint wysyłający najwięcej danych rzadko jest tym wywoływanym najczęściej.

Sprawdź największe assety statyczne. Jeśli cokolwiek większego niż megabajt jest serwowane z aplikacji, to właśnie ten element należy przenieść w pierwszej kolejności.

# What is the service actually doing right now
dockup metrics my-project/my-api --json

# And what is it logging
dockup logs my-project/my-api -n 1000

Obserwuj crawlery. Źle działający bot, który wielokrotnie pobiera duże pliki, może odpowiadać za większość miesięcznego egressu w serwisie o umiarkowanym ruchu użytkowników. robots.txt i noindex w środowiskach preview to tanie rozwiązania.

Środowiska, których nikt nie uwzględnia

Dwa nawyki generują egress, który nie pojawia się w niczyim modelu mentalnym:

Środowiska preview. Środowisko preview dla każdego pull requestu jest naprawdę przydatne, ale po cichu zwielokrotnia zajmowane zasoby. Pięć otwartych PR-ów oznacza pięć kopii stacka, z których każda generuje własny ruch — często pochodzący od tych samych crawlerów, ponieważ URL-e środowisk preview są indeksowane, jeśli im na to nie pozwolisz.

Długowieczny staging. Staging działający od ośmiu miesięcy, którego nikt nie odwiedza, nadal pobiera obrazy, nadal jest skanowany przez crawlery i nadal uruchamia zadania cron.

Żaden z tych przypadków nie jest powodem, żeby z nich rezygnować. Oba są jednak powodem, by wprowadzić ograniczenia: usuwaj środowiska preview po zamknięciu PR-a i oznaczaj je jako noindex, aby wyszukiwarki przestały pobierać je w twoim imieniu.

dockup noindex my-project/my-api --on

Jak powinno wyglądać dobre rozliczanie

Przed otrzymaniem faktury powinieneś umieć odpowiedzieć na trzy pytania:

  1. Co obecnie działa? Uwzględniając również rzeczy, o których zapomniałeś.
  2. Ile zużył każdy element? Z podziałem na compute i transfer, a nie jedną wspólną liczbę.
  3. Co się stanie, jeśli zużycie gwałtownie wzrośnie? Limit, który zatrzymuje usługi, jest nieprzyjemny. Brak limitu jest gorszy.

Dockup rozlicza infrastrukturę oddzielnie od planu, więc opłata za plan nie maskuje faktycznego zużycia — a kredyt w wysokości 20 USD w planie Pro jest naliczany na poczet tego zużycia, zamiast stanowić rabat na opłatę za plan. Chodzi o to, by było jasne, która część dotyczy czego.

W skrócie

Przenieś media do object storage. Ustaw nagłówki cache. Włącz kompresję. Trzymaj usługi i ich bazy danych w jednym regionie i pozwól im komunikować się przez prywatną sieć zamiast publicznego internetu. Usuwaj środowiska preview i wykluczaj je z wyników wyszukiwania.

Tych pięć nawyków rozwiązuje niemal każdy problem z niespodziewanie wysokim rachunkiem za bandwidth, a żaden z nich nie wymaga zmiany miejsca hostingu.

Najczęściej zadawane pytania

Czym jest egress? Dane opuszczające twoją infrastrukturę i kierowane do internetu. Odpowiedzi dla użytkowników, pobierane pliki, payloady API. Ruch przychodzący jest zwykle bezpłatny, a wychodzący — zazwyczaj nie.

Dlaczego mój rachunek za egress jest wyższy niż rachunek za compute? Niemal zawsze dlatego, że aplikacja serwuje pliki, które powinny znajdować się za CDN-em. Jeden duży asset na popularnej stronie może kosztować więcej niż całe tygodnie obsługi żądań.

Czy CDN rzeczywiście zmniejsza te koszty? Tak, jeśli korzysta z cache. Origin serwuje plik raz na każdy edge zamiast raz na każdego użytkownika, a cena CDN-u za gigabajt jest zazwyczaj ułamkiem ceny platformy aplikacyjnej.

Czy środowiska preview kosztują tyle samo co produkcja? Kosztują tyle, ile zużywają, co często oznacza więcej, niż się spodziewasz, ponieważ każde z nich jest pełną kopią, a URL-e środowisk preview są skanowane przez crawlery, jeśli temu nie zapobiegniesz.