Co znajduje się przed niemal każdą usługą webową
Witaj
Jeśli wpiszesz example.com w przeglądarce, niemal nigdy nie dotrzesz do maszyny, która faktycznie uruchamia aplikację. Dotrzesz do maszyny, która przekazuje żądanie do tej, która to robi. Ta maszyna przekazująca ma nazwę: proksy odwrotny.
Ta lekcja uczy, co robi proksy odwrotny, dlaczego niemal każda publiczna usługa webowa ukrywa się za nim oraz jakie trzy zadania warstwa brzegowa wykonuje jednocześnie.
Na koniec zrozumiesz:
- Różnica między klientem, proxy a serwerem źródłowym (origin)
- Dlaczego proxy umieszczone przed serwerem źródłowym (origin) chroni, skaluje oraz pozwala wymieniać komponenty bez zauważenia tego przez użytkowników
- Trzy zadania, które reverse proxy wykonuje jednocześnie: ukrywanie serwera źródłowego, kończenie połączeń TLS oraz dystrybucja obciążenia między replikami
- Jak żądanie podróżuje z przeglądarki do proxy, a następnie do serwera nadrzędnego (upstream) i z powrotem, krok po kroku
Na koniec będziesz potrafił pewnie rozumować na temat rozmieszczenia proxy, podziału obowiązków na krawędzi sieci oraz o tym, dlaczego bezstanowa warstwa proxy łatwo się skaluje, podczas gdy pojedynczy serwer źródłowy nie.
Proxy bezpośredni (Forward) a proxy odwrotny (Reverse)
Dwa kierunki działania proxy
Oba rodzaje proxy znajdują się między dwiema stronami i przekazują ruch. Różnią się tym, którą stronę reprezentują.
Proxy przodujący (forward proxy): stoi przed grupą klientów. Klienci znają istnienie proxy; zewnętrzny serwer widzi adres proxy, a nie adres klienta. Korporacyjne proxy wyjściowe, filtry treści oraz proxy SOCKS pasują do tego wzorca.
Proxy odwrotny (reverse proxy): stoi przed grupą serwerów. Świat zewnętrzny (klienci) komunikuje się z adresem proxy; klienci nie mają pojęcia, że za nim ukrywa się prawdziwy serwer. Prawie każda publiczna usługa internetowa używa takiego rozwiązania.
Mnemotechnika: proxy przodujący ukrywa klientów przed serwerami. Proxy odwrotny ukrywa serwery przed klientami.
Dlaczego ważne jest, w którą stronę działa proxy? Zadania, tryby awarii oraz granica bezpieczeństwa są różne. Proxy przodujący martwi się o to, z kim komunikują się jego użytkownicy; proxy odwrotny martwi się o to, kto komunikuje się z jego serwerami.
Klient wysyłający ruch przez oba typy jednocześnie przechodzi trasę: client -> forward_proxy -> internet -> reverse_proxy -> origin.
Dlaczego tak wiele rzeczy dzieje się na krawędzi
Warstwa krawędziowa zarabia na swoje utrzymanie
Proxy zwrotny wykonuje trzy zadania jednocześnie. Każde z nich samo w sobie uzasadnia istnienie tej warstwy; wykonywanie wszystkich trzech na tym samym adresie wyjaśnia, dlaczego niemal każda produkcyjna architektura webowa ma podobny kształt na froncie.
Zadanie 1: Ukryj źródło. Proxy odpowiada na publicznym adresie IP. Serwery backendowe znajdują się na prywatnych adresach IP, do których internet nie ma dostępu. Atakujący, który chce uderzyć w źródło, musi najpierw przejąć kontrolę nad proxy.
Zadanie 2: Terminowanie TLS. Proxy przechowuje certyfikat dla example.com i dekoduje przychodzące żądania HTTPS. Backendy komunikują się z proxy zwykłym HTTP (lub prostszym wewnętrznym TLS) przez zaufany segment sieci. Rotacja, odnawianie certyfikatów oraz polityka szyfrowania znajdują się w jednym miejscu.
Zadanie 3: Rozkładanie obciążenia. Proxy decyduje, który backend obsłuży każde żądanie. Backendy za jednym proxy tworzą pulę; proxy wybiera jeden z nich dla każdego żądania, stosując określoną strategię (round-robin, najmniej połączeń, hash na podstawie nagłówka). Zwiększanie wydajności oznacza dodanie backendu do puli, a nie informowanie każdego klienta o nowym adresie.
Każde zadanie to mały program. Razem wyjaśniają, dlaczego warstwa tak prosta, jak „Caddy przed aplikacją Python”, niesie na sobie większe znaczenie projektowe niż sama aplikacja Python.
Projektowanie z uwzględnieniem wszystkich trzech zadań
Twoja obsługa uruchamia małe API w pojedynczym procesie Pythona nasłuchującym na porcie 8000 na pojedynczej maszynie wirtualnej. Ruch wzrósł na tyle, że jedna maszyna wirtualna nie jest w stanie nadążyć, a przegląd bezpieczeństwa wskazał, że maszyna wirtualna ma publiczny adres IP i obsługuje własny certyfikat TLS.
Decydujesz się na umieszczenie proxy odwróconego z przodu. Narysuj schemat układu: na co wskazuje DNS, gdzie znajduje się certyfikat, jak obciążenie trafia do backendów oraz co zmienia się w przypadku oryginalnej maszyny wirtualnej?
Wymiana komponentu bez zauważenia przez kogokolwiek
Pośrednictwo daje swobodę
Stare powiedzenie z informatyki głosi: każdy problem można rozwiązać, dodając warstwę pośrednictwa (z wyjątkiem problemu zbyt wielu warstw pośrednictwa). Proxy odwrócony jest jednym z najprzydatniejszych mechanizmów pośrednictwa w systemach rozproszonych.
Co to daje:
- Wymienialne backendy. Przenosisz aplikację z Pythona na Go? Migrujesz z jednego centrum danych do innego? Wdrażasz nową wersję bez przestojów? Każda z tych operacji odbywa się za stabilnym adresem publicznym. Dla użytkowników nic się nie zmienia.
- Niezależne skalowanie. Warstwa proxy skaluje się w oparciu o przepustowość i CPU na warstwie TLS. Warstwa backendu skaluje się w oparciu o obciążenie aplikacyjne. Każda rośnie we własnym wymiarze, ponieważ działają na różnych maszynach.
- Izolacja awarii. Zła aktualizacja na backendzie nie wyłącza adresu publicznego. Proxy pozostaje włączony; wdrażasz poprawkę lub wykonujesz rollback; świat ponownie się łączy, gdy backend odzyskuje sprawność.
- Zagadnienia poprzeczne w jednym miejscu. Ograniczanie przepustowości (rate limiting), blokowanie geograficzne, logowanie żądań, modyfikacja nagłówków, cache'owanie, kompresja odpowiedzi: wszystko to znajduje się na proxy. Kod backendu pozostaje skupiony na samej aplikacji.
Bez proxy każdy z tych problemów musi istnieć wewnątrz procesu aplikacji. Z proxy znajdują się na jednej warstwie, którą obsługuje jeden zespół.
Koszt: kolejna warstwa do obsługi. Dojrzałe zespoły akceptują ten koszt, ponieważ sama warstwa proxy działa bezstanowo (stateless) i skaluje się poziomo; zastąpienie jednego proxy dwoma nie wymaga żadnej koordynacji.
Wdrożenie niebiesko-zielone (Blue/Green) przez proxy
Twoja drużyna uruchamia wersję 1 API na trzech maszynach wirtualnych backendu (pool niebieski) za proxy odwróconym. Chcesz wdrożyć wersję 2 z możliwością cofnięcia zmian w mniej niż trzydzieści sekund, jeśli coś pójdzie nie tak.
Uruchamiasz trzy nowe maszyny wirtualne backendu (pool zielony) z wersją 2, równolegle z pooliem niebieskim, ale jeszcze nie kierujesz do nich żadnego ruchu.
Od przeglądarki do backendu i z powrotem
Śledzenie jednego żądania od początku do końca
Prześledź pojedyncze żądanie HTTPS GET https://api.example.com/users/42 przez proxy odwrotne (reverse proxy) znajdujące się przed pulą backendów.
Hop 1: Rozdzielczość DNS. Przeglądarka pyta resolver o api.example.com. Resolver zwraca publiczny adres IP proxy (np. 203.0.113.10). Przeglądarka otwiera połączenie TCP z 203.0.113.10:443.
Hop 2: Rękościk TLS. Proxy przedstawia swój certyfikat dla api.example.com. Przeglądarka weryfikuje certyfikat, obie strony uzgadniają klucz sesji, a kanał szyfrowany zostaje otwarty.
Hop 3: Żądanie HTTP wewnątrz TLS. Przeglądarka wysyła GET /users/42 HTTP/1.1\nHost: api.example.com\n.... Proxy odszyfrowuje bajty żądania.
Hop 4: Wybór backendu. Proxy konsultuje swój pulę upstream dla api.example.com i wybiera jeden backend (np. 10.0.0.21:8000) zgodnie ze swoją strategią równoważenia obciążenia.
Hop 5: Żądanie upstream. Proxy otwiera (lub ponownie wykorzystuje) zwykłe połączenie HTTP z 10.0.0.21:8000 i przesyła żądanie. Proxy może modyfikować nagłówki w trakcie przesyłania: dodać X-Forwarded-For: <client-ip>, poprawnie ustawić Host: oraz usunąć nagłówki hop-by-hop, takie jak Connection.
Hop 6: Przetwarzanie w backendzie. Aplikacja backendowa odczytuje żądanie, zapytuje swoją bazę danych i buduje odpowiedź w formacie JSON.
Hop 7: Odpowiedź upstream. Backend wysyła odpowiedź z powrotem do proxy jako zwykły HTTP.
Hop 8: Odpowiedź na krawędzi. Proxy może modyfikować lub kompresować odpowiedź, szyfruje ją z powrotem przez sesję TLS i wysyła ją do przeglądarki.
Hop 9: Cykl życia połączenia. Sesja TLS zazwyczaj pozostaje otwarta dla następnego żądania (HTTP/2 multiplexuje wiele żądań na jednym połączeniu). Połączenie proxy z backendem jest często utrzymywane w puli w celu ponownego użycia.
Każdy publiczny serwis webowy podąża za pewną wariantem tego schematu. Znajomość poszczególnych hopów pozwala wnioskować, gdzie gromadzi się opóźnienie, gdzie należy prowadzić logi oraz gdzie może ukrywać się awaria.
Gdzie zniknął czas?
Użytkownik skarży się, że API wydaje się wolne. Mierzysz i stwierdzasz, że żądanie trwa 850 ms od początku do końca. Logi serwera na backendzie pokazują, że aplikacja obsłużyła żądanie w 40 ms. Logi proxy pokazują, że proxy spędziło 50 ms na swojej części pracy (handshake TLS + routing + zapis odpowiedzi).
Zaprojektuj minimalną warstwę brzegową dla nowej usługi
Synteza
Poznałeś różnicę między proxy przodem a proxy wstecznym, trzy zadania, które proxy wsteczny wykonuje jednocześnie, dlaczego ukrywanie źródła (origin) przynosi korzyści za każdym razem, gdy trzeba coś zmienić, oraz jak żądanie przepływa hop po hopie przez warstwę brzegową.
Teraz zastosuj tę wiedzę.
Mały zespół planuje uruchomienie nowej usługi o nazwie notes.example.com. Użytkownicy będą czytać i pisać osobiste notatki. Zespół uruchomi dwie maszyny wirtualne (VM) na serwerze backendowym na starcie i oczekuje, że w ciągu najbliższego roku skaluje się do dziesięciu. Chcą HTTPS dla użytkowników, stopniowe wdrażanie nowych wersji oraz brak publicznego ujawniania adresów IP serwerów backendowych.
Kierunek dalszego rozwoju tego kursu
Kierunek dalszego rozwoju tego kursu
Ta lekcja zdefiniowała strukturę warstwy brzegowej (edge layer). Cztery kolejne lekcje w tym kursie budują na jej fundamentach:
- Be Stanowe Skalowanie Poziome (Stateless Horizontal Scaling): dlaczego warstwa proxy (oraz backendy za nią) skaluje się tanio, oraz matematyka do wyznaczania liczby replik w przypadku nagłego wzrostu ruchu (surge).
- Rozdzielenie Ruchu Przyjmującego i Wysyłającego (Ingress / Egress Separation): dlaczego pojedynczy serwer proxy obsługujący zarówno ruch przychodzący, jak i wychodzący ostatecznie zawodzi w zaskakujący sposób, oraz jak rozdzielić te warstwy.
- Tryby awarii i zasięg skutków: jak pojedyncza zmiana konfiguracji może prowadzić do awarii oraz jak pisać bezosobowe punkty działań, które zapobiegają powtórzeniu się incydentu.
- Obserwowalność i pojemność: co mierzyć na krawędzi sieci, aby wykryć usterkę, zanim zrobią to użytkownicy.
Każda lekcja jest samodzielnym elementem. Rozważane łącznie, tworzą one działający model mentalny floty o skali webowej.
Lekcja towarzysząca: geometry_of_proxies_and_origins przedstawia wszystko z tej lekcji jako graf skierowany i bada, co teoria grafów mówi o ścieżce żądania.
Bardzo dobrze. Dalej.