Powrót do bloga

Nginx: pośredniczenie HTTP, równoważenie obciążenia, buforowanie i pamięć podręczna – przegląd

Nginx: pośredniczenie HTTP, równoważenie obciążenia, buforowanie i pamięć podręczna – przegląd
Wprowadzenie

Nginx to wydajny serwer WWW, który jest również używany jako reverse proxy, proxy pocztowe, load balancer i pamięć podręczna HTTP. Nginx jest darmowy i ma otwarte źródło, co pozwala każdemu na pobranie i używanie go w swoim środowisku serwerowym.

Być może używałeś już Nginx do obsługi stron internetowych. W tym samouczku omówimy inne możliwości Nginx. Pośredniczenie HTTP serwera Nginx pozwala mu na przekazywanie żądań do serwerów HTTP backendu w celu ich przetworzenia. Dzięki tej funkcji możesz skonfigurować wiele serwerów backendowych. Pozwala to na skalowanie infrastruktury w zależności od potrzeb, aby radzić sobie z nagłymi wzrostami liczby żądań klientów.

W miarę postępów w samouczku dowiesz się o skalowaniu infrastruktury przy użyciu właściwości Nginx do równoważenia obciążenia, buforowania oraz zapisywania w pamięci podręcznej odpowiedzi, aby poprawić wydajność serwera, a także zapewnić lepsze wrażenia dla klientów. Zacznijmy!

Po pierwsze, aby rozpocząć pracę z Nginx, zapoznaj się z naszym samouczkiem dotyczącym instalacji Nginx na serwerze Ubuntu.

Ogólne informacje o pośredniczeniu

Jeśli Twoja wiedza o serwerach WWW ogranicza się tylko do przetwarzania żądań stron internetowych i serwowania stron, możesz się zastanawiać, dlaczego musimy pośredniczyć w żądaniach. Poniżej wyjaśnimy przyczyny tego stanu rzeczy.

Jednym z powodów przekazywania żądań do innych serwerów z poziomu Nginx jest wsparcie skalowalności infrastruktury. Nginx domyślnie obsługuje wiele połączeń jednocześnie. To sprawia, że idealnie nadaje się jako pierwszy punkt kontaktu dla klientów. Następnie może przekazywać żądania do różnych serwerów backendowych w celu faktycznego przetworzenia żądań klientów. To właśnie rozkłada obciążenie. Dzięki temu zapewnia możliwość maksymalnego skalowania infrastruktury. Umożliwia to również wyłączenie niektórych serwerów w celu konserwacji, podczas gdy inne nadal obsługują żądania.

Drugim powodem, dla którego możesz chcieć przekazywać żądania do innych serwerów, jest sytuacja, gdy używasz serwerów aplikacji, które nie są odpowiednie do bezpośredniej obsługi żądań od klientów w produkcyjnych środowiskach uruchomieniowych. Kilka frameworków, w tym serwerów WWW, nie nadaje się do pracy z wysoką wydajnością, taką jak Nginx. Pozwolenie Nginx na bycie punktem wejścia i pośredniczenie w żądaniach do tych mniej wydajnych serwerów może zapewnić użytkownikom lepsze wrażenia. Dodatkowo może to zagwarantować większe bezpieczeństwo Twojej aplikacji.

Proces pośredniczenia w żądaniach w Nginx polega na modyfikowaniu żądania z serwera Nginx i przekazywaniu go do innych serwerów backendowych w celu faktycznego przetworzenia. Gdy inne serwery backendowe przetworzą żądanie, przekazują wynik z powrotem do Nginx. Następnie wysyła on wynik jako odpowiedź do klienta. Klientem w tym przypadku jest przeglądarka internetowa lub nawet mobilna aplikacja internetowa. Inne serwery backendowe mogą być serwerami lokalnymi, które nie są publicznie dostępne w Internecie, serwerami zdalnymi, a nawet innymi serwerami wirtualnymi w konfiguracjach bloków serwerów Nginx. Te inne serwery, do których Nginx przekazuje żądania, są określane jako serwery upstream.

Nginx może pośredniczyć w żądaniach do serwerów komunikujących się za pomocą kilku protokołów, w tym HTTP(S), Memcached, SCGI, FastCGI oraz uWSGI. Dla każdego typu protokołu istnieją zestawy dyrektyw. W tym samouczku skupiamy się na protokole HTTP. Nginx analizuje żądania i komponenty komunikatów na format, który serwer upstream może zinterpretować i przetworzyć.

Analiza podstawowego przekazywania proxy HTTP

Najprostszy typ proxy polega na przekazywaniu żądania do pojedynczego serwera, który komunikuje się przez HTTP. Ten typ proxy jest ogólnie określany jako „proxy pass” i jest obsługiwany przez trafnie nazwaną dyrektywę proxy_pass w plikach konfiguracyjnych Nginx.

Dyrektywa proxy_pass pojawia się wewnątrz bloków location. Znajduje się również w blokach kontekstu location oraz w kontekstach limit_except. Gdy żądanie pasuje do lokalizacji z dyrektywą proxy_pass wewnątrz, żądanie trafia pod adres URL określony przez tę dyrektywę. Poniżej znajduje się przykład fragmentu konfiguracji:

proxy_pass_conf

W powyższym przykładzie żądania kierowane do portu 80 trafiałyby do localhost:3000:

nginx default page

Powyższy zrzut ekranu przedstawia domyślną stronę Nginx przy próbie połączenia z localhost. Po zrestartowaniu serwera Nginx z włączoną dyrektywą proxy_pass wszystkie żądania będą kierowane na port 3000. Na porcie 3000 działa aplikacja demonstracyjna, co widać na poniższym obrazku, i można do niej dotrzeć bezpośrednio z localhost bez podawania portu:

localhost after applying proy pass

W kolejnym przykładzie na końcu adresu serwera w definicji proxy_pass nie określono żadnego identyfikatora URI. W przypadku definicji pasujących do tego wzorca, URI żądany przez klienta zostanie przekazany do serwera upstream w niezmienionej postaci.

Na przykład, gdy ten blok obsługuje żądanie dla /match/url/here, URI żądania trafi do serwera example.com jako http://example.com/match/url/here.

Poniżej znajduje się przykład alternatywnego fragmentu konfiguracji:

Jak widać w powyższym fragmencie, na końcu serwera proxy zdefiniowaliśmy segment URI jako new/url/prefix. Kiedy definiujesz URI w definicji proxy_pass, część żądania pasująca do definicji lokalizacji (location) jest zastępowana tym URI podczas przekazywania do serwera upstream w celu przetworzenia.

Na przykład żądanie skierowane do /match/url/here na serwerze Nginx jest przekazywane do serwera upstream jako http://example.com/new/url/here. Część /match/url zostaje zastąpiona przez /new/url. Warto o tym pamiętać.

W niektórych przypadkach przekazywanie identyfikatorów URI w powyższy sposób nie jest możliwe. W takich sytuacjach Nginx ignoruje URI na końcu definicji proxy_pass. Ostatecznie do serwera upstream przekazywany jest pierwotny URI od klienta lub URI zmodyfikowany przez inne dyrektywy.

Przykładem jest sytuacja, gdy wyrażenia regularne pasują do lokalizacji (location). Nginx może nie być w stanie określić, która część URI pasuje do wyrażenia. W związku z tym wysyła oryginalny URI żądania klienta. Powoduje to przepisywanie (rewriting) i obsługę URI klienta w tym samym bloku. W takim przypadku przekazywany jest przepisany URI.

Jak Nginx przetwarza nagłówki?

Nagłówki mają kluczowe znaczenie dla sposobu, w jaki serwer przetwarza żądanie. Niektóre nagłówki mogą zawierać informacje uwierzytelniające. Dlatego musimy zrozumieć, jak proxying w Nginx przetwarza nagłówki. Żądanie proxy z Nginx do serwera upstream będzie wyglądać inaczej niż to, które przyszło bezpośrednio od klienta. Niektóre z różnic wynikają z nagłówków, które towarzyszą żądaniu proxy.

Podczas przekazywania żądania (proxyingu) Nginx dostosuje nagłówki żądania otrzymane od klienta. Niektóre z tych dostosowań obejmują:

  • Usuwanie wszystkich pustych nagłówków. Puste nagłówki tylko niepotrzebnie powiększają żądanie, więc nie ma sensu przekazywać ich do serwera upstream.

  • Wszelkie nagłówki zawierające podkreślenia są domyślnie uznawane za nieprawidłowe, a tym samym usuwane z żądania. Jeśli chcesz zmienić to zachowanie i pozwolić Nginx interpretować nagłówki z podkreśleniami jako prawidłowe, możesz ustawić dyrektywę underscores_in_headers na „on”. Jeśli tego nie zrobisz, takie nagłówki od klienta nigdy nie dotrą do serwera upstream.

  • Nagłówek „Host” jest nadpisywany wartością określoną przez zmienną $proxy_host. Jest to adres IP lub nazwa i numer portu serwera upstream, zgodnie z definicją w dyrektywie proxy_pass.

  • Wartość nagłówka „Connection” zmienia się na „close”. Nagłówek połączenia zawiera informacje o konkretnym połączeniu ustanowionym między dwiema stronami. Gdy Nginx ustawia jego wartość na „close”, wskazuje serwerowi upstream, że połączenie zostanie zamknięte po udzieleniu odpowiedzi na pierwotne żądanie, więc nie powinno ono być oczekiwane jako połączenie trwałe.

Oto kilka kwestii, na które warto zwrócić uwagę w związku z opisanymi powyżej modyfikacjami nagłówków żądań proxy:

  • Jeśli nie chcesz, aby nagłówek był przekazywany do serwera nadrzędnego, ustawienie go jako pusty ciąg znaków całkowicie usunie go z żądania.

  • Jeśli aplikacja na serwerze nadrzędnym będzie przetwarzać niestandardowe nagłówki, upewnij się, że nagłówki te nie zawierają podkreślenia. Opcjonalnie możesz ustawić dyrektywę underscores_in_headers na „on” w swojej konfiguracji (obowiązuje to zarówno w kontekście domyślnej deklaracji serwera dla kombinacji adresu IP/portu, jak i w kontekście HTTP). Zapewni to, że nagłówki nie zostaną oznaczone jako nieprawidłowe i tym samym zostaną faktycznie przekazane do serwera nadrzędnego.

  • Nagłówek „Host” jest bardzo ważny w większości sytuacji związanych z proxy. Domyślnie jest on ustawiony na wartość $proxy_host, zmienną zawierającą nazwę domeny lub adres IP i port pobrane ze specyfikacji proxy_pass. Adres ten jest wybierany domyślnie i pobierany bezpośrednio z informacji o połączeniu. Jest to jedyny adres, co do którego Nginx ma gwarancję, że serwer nadrzędny na niego odpowie.

Poniżej przedstawiono najczęstsze wartości nagłówka „Host”:

  • $host – zmienna ustawiana w kolejności preferencji na nazwę hosta z samego wiersza żądania, nagłówek „Host” z żądania klienta lub nazwę serwera pasującą do żądania.

  • $http_host – zmienna, która ustawia nagłówek „Host” na nagłówek „Host” z żądania klienta. Nagłówki w żądaniu klienta są zawsze dostępne dla Nginx jako zmienne. Zmienne te zaczynają się od przedrostka $http_, po którym następuje nazwa nagłówka pisana małymi literami. Chociaż zmienna $http_host w większości przypadków będzie działać poprawnie, brak prawidłowego nagłówka „Host” w żądaniu klienta może spowodować niepowodzenie przekazania.

  • $proxy_host – zmienna, która ustawia nagłówek „Host” na kombinację nazwy domeny lub adresu IP i portu pobraną ze specyfikacji proxy_pass. Jest to domyślne zachowanie z punktu widzenia Nginx i dlatego jest uważane za bezpieczne. Może to jednak nie być to, czego serwer potrzebuje do prawidłowej obsługi żądania.

Większość konfiguracji będzie polegać na ustawieniu nagłówka „Host” na zmienną $host. Jest to wysoce elastyczne rozwiązanie i zapewni dokładne wypełnienie nagłówków przekazywanych do serwera nadrzędnego.

Ustawianie i modyfikowanie nagłówków

Dyrektywa proxy_set_header pozwala nam ustawiać lub modyfikować nagłówki dla połączeń proxy. W przypadku omówionego wcześniej nagłówka „Host” możemy wykonać następujące czynności, aby zmodyfikować i dodać dodatkowe nagłówki powszechne w przypadku żądań proxy:

W powyższym fragmencie konfiguracji ustawiamy nagłówek „Host” na zmienną $host, która zawiera informacje o oryginalnym żądanym hoście. Ustawiamy nagłówek X-Forwarded-Proto z informacją o schemacie oryginalnego żądania od klienta (może to być żądanie HTTP lub HTTPS).

Przekazujemy rzeczywisty adres IP klienta do nagłówka X-Real-IP. Umożliwia to serwerowi nadrzędnemu podejmowanie odpowiednich decyzji lub zapisywanie logów na podstawie adresu IP klienta. Nagłówek X-Forwarded-For zawiera listę wszystkich adresów IP należących do serwerów, przez które klient był przekierowywany przed dotarciem do tego miejsca. W powyższym fragmencie kodu ustawiamy go na zmienną $proxy_add_x_forwarded_for. Zmienna ta przyjmie wartość oryginalnego nagłówka X-Forwarded-For pobranego od klienta i doda na końcu adres IP serwera proxy Nginx.

Jeśli chcesz, aby dyrektywy proxy_set_header były przywoływane w więcej niż jednej lokalizacji, możesz przenieść je do kontekstu server lub http. Rozważ poniższy fragment konfiguracji:

Definiowanie kontekstu upstream do równoważenia obciążenia przekazywanych połączeń

Do tego momentu wiesz już, jak skonfigurować proste proxy HTTP do pojedynczego serwera upstream w backendzie. Na szczęście dzięki Nginx możesz skalować taką konfigurację, definiując pule serwerów backendowych, do których będą przekazywane żądania w celu ich obsłużenia.

Nginx udostępnia dyrektywę o nazwie upstream, która służy do definiowania puli serwerów. W konfiguracji tej dyrektywy należy określić wyłącznie serwery, które są w stanie obsłużyć żądanie klienta. Nginx jako serwer proxy pozwala na skalowanie infrastruktury przy minimalnym wysiłku. Dyrektywa upstream musi być określona w kontekście http konfiguracji Nginx.

Oto przykład pokazujący dyrektywę upstream:

W powyższym fragmencie kodu konfiguracyjnego zdefiniowaliśmy kontekst upstream o nazwie several_backend_hosts. Zdefiniowana nazwa kontekstu jest teraz dostępna w ramach przekazywania proxy (proxy pass). Może być używana tak, jakby była zwykłą domeną, jak pokazano w przykładzie. W bloku server przekazujemy wszystkie żądania kierowane do example.com/proxy-me/… do zdefiniowanej przez nas puli za pomocą dyrektywy upstream, w tym przypadku several_backend_hosts. Host z puli jest wybierany do obsługi nadchodzących żądań przy użyciu konfigurowalnego algorytmu. Domyślnie wybór odbywa się zgodnie z procesem round-robin (okrężnym) – każde żądanie jest po kolei kierowane do innego hosta.

Jak zmienić algorytm równoważenia obciążenia upstream

Jak zaznaczono powyżej, proces wyboru odbywa się zgodnie z metodą round-robin. W tej sekcji zobaczymy, jak możemy zmodyfikować algorytm równoważenia używany przez pulę upstream. Aby zmodyfikować algorytm, należy dołączyć inne dyrektywy lub flagi w kontekście upstream, jak opisano poniżej:

  • (round-robin) – jeśli nie określono żadnej innej dyrektywy równoważenia upstream, domyślnie każde żądanie jest przekazywane sekwencyjnie do kolejnych serwerów zdefiniowanych w kontekście upstream.

  • least_conn – ta dyrektywa instruuje upstream, aby wybrać serwer backendowy z najmniejszą liczbą aktywnych połączeń. Ma to zastosowanie w sytuacjach, gdy połączenia z jednym serwerem backendowym mogą utrzymywać się przez dłuższy czas.

  • hash – ta dyrektywa jest powszechnie stosowana przy proxy do memcached. Połączenia są przekazywane do serwerów backendowych na podstawie wartości losowo dostarczonego klucza skrótu (hash). Wartością klucza skrótu mogą być zmienne, tekst lub ich kombinacja. hash jest jedyną metodą równoważenia, która wymaga danych wejściowych od użytkownika, aby służyły jako klucz używany do haszowania.

  • ip_hash – ta dyrektywa instruuje upstream, aby dystrybuować żądania do różnych serwerów na podstawie adresu IP klienta. Pierwsze trzy oktety adresu IP stanowią klucz do określenia, który serwer powinien obsłużyć żądanie. Zaletą tej dyrektywy jest to, że klienci zazwyczaj trafiają za każdym razem na ten sam serwer, co zapewnia spójność sesji.

Oto przykład, jak możemy dodać dyrektywę algorytmu równoważenia do kontekstu upstream:

W powyższym fragmencie kodu Nginx wybierze dowolny z serwerów o najmniejszej liczbie połączeń do obsłużenia przychodzącego żądania. Dyrektywa ip_hash ma taką samą składnię. W przypadku dyrektywy hash należy podać wybrany klucz, na podstawie którego zostanie utworzony skrót (hash). Oto przykład:

Użyty tutaj skrót (hash) będzie wynikiem adresu IP i portu klienta. Opcjonalny parametr consistent implementuje algorytm spójnego haszowania Ketama. Zapewnia to minimalny wpływ na pamięć podręczną w przypadku zmiany serwerów upstream.

Jak określić wagę serwera dla równoważenia obciążenia

Domyślnie, podczas deklarowania serwerów backendowych, każdy serwer ma przypisaną taką samą wagę. Zakłada się, że każdy serwer posiada zasoby i możliwości do obsłużenia takiej samej ilości obciążenia, oczywiście biorąc pod uwagę algorytm równoważenia określony w kontekście upstream. Aby zmienić to domyślne zachowanie, można ustawić alternatywną wagę dla każdego serwera podczas deklaracji. Rozważmy przykład:

W tym przykładzie host1.example.com otrzyma dwa razy więcej ruchu niż pozostałe dwa serwery. Domyślna waga dla każdego serwera wynosi jeden.

Zwalnianie serwerów backendowych za pomocą buforów

Podczas konfigurowania proxy w konfiguracji serwera możesz obawiać się wpływu dodania kolejnych serwerów na wydajność. Na szczęście Nginx oferuje funkcje buforowania i pamięci podręcznej, które mogą pomóc złagodzić te problemy z wydajnością.

Prędkość dwóch różnych połączeń z pewnością wpłynie na wrażenia klienta podczas przekierowywania żądań (proxy) do innego serwera:

  • Pierwsze połączenie to połączenie od klienta do proxy Nginx.

  • Drugie połączenie to połączenie od proxy Nginx do serwera backendowego upstream.

Nginx może dostosować swoje zachowanie, aby w razie potrzeby pomóc zoptymalizować dowolne z tych połączeń.

Jeśli wyłączymy bufory, dane z backendu upstream zaczną być natychmiast przesyłane do klienta przez proxy Nginx. Jeśli wiesz, że Twoi klienci mają szybkie połączenia, możesz całkowicie wyłączyć buforowanie, aby dane docierały do nich wystarczająco szybko. Gdy buforowanie jest włączone, proxy Nginx tymczasowo przechowuje dane odpowiedzi otrzymane z serwera backendowego upstream. Następnie wysyła te dane do klienta w zależności od jego prędkości. Gdy Nginx ma już odpowiedź w swoich buforach, może zamknąć połączenie z serwerem backendowym. Następnie przekaże dane klientowi z prędkością, którą ten obsługuje. Jednocześnie pozwala to serwerowi backendowemu na dalsze przetwarzanie innych przychodzących żądań.

Domyślnie Nginx ma włączone buforowanie. Wynika to z faktu, że nie możemy znać prędkości połączeń klientów. Klienci zazwyczaj mają różne połączenia, które mogą być wolniejsze. Poniżej zdefiniujemy różne dyrektywy, które możemy określić, aby dostosować zachowanie buforowania Nginx. Dyrektywy te mogą być definiowane w kontekstach http, server lub location, należy jednak pamiętać, że dyrektywy dotyczące rozmiaru są konfigurowane na żądanie. W związku z tym zwiększenie ich ponad to, co jest absolutnie konieczne, może wpłynąć na wydajność serwera przy zbyt dużej liczbie przychodzących żądań klientów. Oto te dyrektywy:

  • proxy_buffering – dyrektywa kontrolująca, czy buforowanie jest aktywne dla określonego kontekstu i kontekstów podrzędnych. Domyślna konfiguracja dla proxy_buffering to „on”.

  • proxy_buffer_size – dyrektywa określająca rozmiar bufora do przechowywania nagłówków znajdujących się w odpowiedzi z serwera backendowego. Nagłówki stanowią pierwszą część odpowiedzi z serwera backendowego. Buforowanie tych nagłówków jest oddzielone od reszty odpowiedzi. Domyślnie ustawiony rozmiar tego bufora jest taki sam jak dla proxy_buffers. Jeśli jednak informacje w nagłówku są niewielkie, można ustawić mniejszy rozmiar.

  • proxy_buffers – dyrektywa kontrolująca liczbę (pierwszy argument) i rozmiar (drugi argument) buforów dla przekazywanych odpowiedzi. Domyślna konfiguracja określa 8 buforów o rozmiarze równym jednej stronie pamięci (4k lub 8k). Możesz zezwolić na buforowanie większej ilości informacji, zwiększając liczbę buforów.

  • proxy_max_temp_file_size – dyrektywa określająca maksymalny rozmiar pliku tymczasowego na dysku na jedno żądanie. Pliki tymczasowe są tworzone, gdy odpowiedź z serwera upstream jest zbyt duża, aby zmieścić się w buforze.

  • proxy_busy_buffers_size – dyrektywa określająca maksymalny rozmiar buforów, które mogą zostać oznaczone jako „gotowe dla klienta” (client-ready), a tym samym zajęte. Klient może czytać dane tylko z jednego bufora naraz. Jednak bufory znajdują się w kolejce do wysłania do klienta w partiach. Możesz określić rozmiar przestrzeni bufora, która może znajdować się w tym stanie, modyfikując tę dyrektywę.

  • proxy_temp_file_write_size – dyrektywa określająca ilość danych, które Nginx zapisze jednorazowo do pliku tymczasowego, gdy odpowiedź z serwera backendowego upstream jest zbyt duża, aby zmieścić się w skonfigurowanych buforach.

  • proxy_temp_path – dyrektywa określająca ścieżkę do lokalizacji na dysku, w której Nginx powinien przechowywać pliki tymczasowe, gdy odpowiedź z serwera backendowego upstream jest zbyt duża, aby zmieścić się w skonfigurowanych buforach.

Nginx jest wysoce konfigurowalny, oferując kilka dyrektyw do dostosowania zachowania buforowania. W większości przypadków wartości domyślne sprawdzą się doskonale. Jednocześnie warto wiedzieć, że można dostosować niektóre z tych wartości do własnej implementacji. Najczęściej będziesz chciał dostosować dyrektywy proxy_buffers i proxy_buffer_size.

Poniżej znajduje się przykład, który zwiększa liczbę dostępnych buforów proxy dla każdego żądania upstream. Robi to przy jednoczesnym zmniejszeniu rozmiaru bufora przechowującego nagłówki:

Zobaczmy, jak można szybciej dostarczać dane do szybkich klientów poprzez całkowite wyłączenie buforowania. Jeśli okaże się, że Twój klient nie jest wystarczająco szybki, Nginx automatycznie użyje buforów. Jednak najpierw prześle dane do klienta, zamiast czekać na pule buforów. Taka konfiguracja ma jednak wadę. Powoduje ona, że połączenie z serwerem upstream pozostaje otwarte dla wolnych klientów, dopóki klient nie otrzyma wszystkich danych odpowiedzi. Jeśli buforowanie jest ustawione na „off”, używany będzie tylko bufor zdefiniowany przez dyrektywę proxy_buffer_size. Oto fragment pokazujący, jak określić wyłączenie buforowania:

  • Konfigurowanie infrastruktury o wysokiej dostępności (HA) (Opcjonalna konfiguracja)

Możesz dodać nadmiarowy zestaw modułów równoważenia obciążenia do konfiguracji serwera proxy Nginx, zapewniając jej większą niezawodność, a tym samym wysoką dostępność. Konfiguracja wysokiej dostępności (HA) to infrastruktura bez pojedynczego punktu awarii. Moduły równoważenia obciążenia są częścią tej konfiguracji. Posiadając więcej niż jeden moduł równoważenia obciążenia, możesz zapobiec potencjalnym przestojom, jeśli jeden z nich ulegnie awarii lub zostanie wyłączony w celu konserwacji.

Jak wdrożyć buforowanie proxy Nginx w celu skrócenia czasu reakcji

W poprzedniej sekcji omówiliśmy, jak używać buforowania, aby odciążyć serwery backendowe i umożliwić im obsługę większej liczby żądań. Nginx oferuje kolejną funkcję, która pozwala nam buforować dane odpowiedzi z backendu. Całkowicie eliminuje to potrzebę łączenia się z serwerem nadrzędnym (upstream) dla wszystkich przychodzących żądań.

Wdrażanie pamięci podręcznej proxy

Dyrektywa proxy_cache_path pozwala nam skonfigurować pamięć podręczną poprzez określenie obszaru na dysku, który ma być używany do przechowywania buforowanej zawartości. Dyrektywa proxy_cache_path jest definiowana w kontekście http.

Poniższy fragment kodu konfiguracyjnego jest przykładem wdrożenia systemu buforowania:

W tym fragmencie kodu użyliśmy dyrektywy proxy_cache_path do zdefiniowania katalogu w systemie plików, który będzie przechowywał naszą pamięć podręczną. W tym przypadku ustawiliśmy katalog /var/lib/nginx/cache. Możesz zdefiniować dowolną ścieżkę katalogu. Użyj następujących poleceń, aby utworzyć wybrane katalogi z odpowiednimi uprawnieniami i własnością:

W tym fragmencie kodu parametr levels= określa strukturę pamięci podręcznej. Nginx utworzy klucz pamięci podręcznej poprzez zahaszowanie wartości klucza (określonego za pomocą dyrektywy proxy_cache_key). Określone przez nas poziomy (1:2) wskazują, że zostanie utworzony katalog o nazwie składającej się z jednego znaku (tj. ostatniego znaku zahaszowanej wartości) z podkatalogiem o nazwie składającej się z dwóch znaków (pobranych z kolejnych dwóch znaków od końca zahaszowanej wartości). W większości przypadków nie będzie to miało dla Ciebie znaczenia. Warto jednak wiedzieć, jak pomaga to serwerowi Nginx w szybkim odnajdywaniu odpowiednich wartości.

Parametr keys_zone= definiuje nazwę strefy pamięci podręcznej, w naszym przypadku nazwaliśmy ją backendcache. Tutaj określamy również, ile metadanych chcemy przechowywać. W tym przykładzie przechowujemy 8 MB kluczy. Nginx może pomieścić około 8000 wpisów na każdy megabajt. Parametr max_size określa maksymalny rozmiar rzeczywistych buforowanych danych, w naszym przykładzie jest to 50MB.

Należy również zwrócić uwagę na użytą dyrektywę proxy_cache_key. Dyrektywa ta określa klucz, którego użyjemy do przechowywania buforowanych wartości. Tego samego klucza użyjemy do sprawdzenia, czy żądanie istnieje w pamięci podręcznej. Określiliśmy, że klucz ten będzie kombinacją schematu (http lub https), metody żądania HTTP oraz żądanego hosta i identyfikatora URI.

Dodatkowo użyliśmy dyrektywy proxy_cache_valid. Dyrektywę tę można określić wielokrotnie dla różnych kodów statusu. Pozwala nam ona określić, jak długo przechowywać wartości w zależności od kodu statusu. W tym fragmencie kodu określiliśmy 10 minut dla kodów sukcesu i 1 minutę dla odpowiedzi 404.

Po skonfigurowaniu strefy pamięci podręcznej kolejnym krokiem jest wdrożenie konfiguracji w życie poprzez poinformowanie serwera Nginx, kiedy ma korzystać z pamięci podręcznej. Poniżej znajduje się fragment konfiguracji pokazujący, jak możemy wdrożyć korzystanie z tej pamięci podręcznej:

W dyrektywie proxy_cache określiliśmy, że dla tego kontekstu powinna być używana strefa pamięci podręcznej backendcache. Jeśli w konfiguracji pamięci podręcznej wybrałeś inną nazwę, w tym miejscu należy ją zastąpić. Dla każdego prawidłowego wpisu Nginx sprawdzi pamięć podręczną przed przekazaniem żądania do serwera backendowego upstream.

Definiujemy dyrektywę proxy_cache_bypass, aby użyć zmiennej $http_cache_control. Zmienna ta informuje serwer, czy powinien odpowiedzieć wersją z pamięci podręcznej, czy też świeżą, niebuforowaną wersją zasobu. Odpowiednie ustawienie tej dyrektywy pozwala serwerowi Nginx na prawidłową obsługę różnych typów żądań przychodzących od klientów.

Określono również dodatkowy nagłówek o nazwie X-Proxy-Cache. Nagłówek ten przyjmuje wartość zmiennej $upstream_cache_status. Dostarcza nam informacji o tym, czy żądanie zakończyło się trafieniem w pamięć podręczną (cache hit), brakiem w pamięci podręcznej (cache miss), czy też pamięć podręczna została jawnie pominięta. Takie informacje mogą być przydatne dla klienta i kluczowe podczas debugowania aplikacji.

Ważne kwestie dotyczące buforowania wyników

Chociaż buforowanie znacznie poprawi wydajność serwera proxy, podczas wdrażania buforowania należy wziąć pod uwagę następujące kwestie:

Wszelkie dane powiązane z danymi osobowymi użytkownika nie powinny być buforowane, aby uniknąć sytuacji, w których dane jednego użytkownika są widoczne dla innego użytkownika.

Serwery backendowe powinny uwzględniać wszystkie dynamiczne elementy witryny. Istnieje kilka nagłówków Cache-Control, które możemy określić w naszej odpowiedzi, aby służyły różnym celom. Omówmy je:

  • no-cache – określa, że proxy musi sprawdzić, czy dane uległy zmianie na backendzie przed dostarczeniem odpowiedzi. Ma to zastosowanie do dynamicznych i ważnych danych. Nagłówek metadanych z hashem ETag jest sprawdzany przy każdym żądaniu i jeśli backend zwróci tę samą wartość skrótu (hash), serwowana jest poprzednia wartość.

  • no-store – określa brak buforowania dla jakichkolwiek odebranych danych, stąd każde żądanie zostanie skierowane do serwera po świeże dane. Jest to najbezpieczniejsze rozwiązanie dla poufnych danych.

  • private – określa, że żadna wspólna przestrzeń pamięci podręcznej nie powinna buforować danych. Możesz użyć tego nagłówka, aby określić buforowanie w przeglądarce użytkownika, ale także poinformować serwer proxy, aby uznał dane za nieważne dla kolejnych żądań.

  • public – określa odpowiedź publiczną i umożliwia buforowanie w dowolnym punkcie połączenia.

Możesz określić, jak długo pamięć podręczna ma być przechowywana (w sekundach), używając nagłówka max-age. Różne nagłówki zdefiniowane powyżej mogą pomóc we wdrożeniu buforowania przy jednoczesnym zapewnieniu bezpieczeństwa poufnych danych, świeżości danych dynamicznych i, co najważniejsze, poprawie wydajności serwera.

Jeśli Twoje serwery backendowe działają na serwerach Nginx, możesz określić w blokach server, jak długo pamięć podręczna powinna być ważna. Możesz to zrobić, dodając dyrektywę expires do konfiguracji, jak pokazano poniżej:

Pierwszy blok pozwala na buforowanie zawartości przez 59 minut, podczas gdy drugi blok wskazuje na brak buforowania. Ustawienia te mają zastosowanie do opcji nagłówków Cache-Control, na przykład „no-cache” dla drugiego bloku.

Możesz użyć dyrektywy add-header, aby ustawić dodatkowe wartości:

Podsumowanie

W tym samouczku poznaliśmy potężne funkcje serwera Nginx. Nginx jest zarówno serwerem WWW, jak i, co najważniejsze, odwrotnym proxy. Konstrukcja Nginx pozwala mu na obsługę tysięcy jednoczesnych połączeń. Dzięki temu idealnie nadaje się do równoważenia obciążenia. Ze względu na tę konstrukcję, przekazywanie żądań do innych serwerów backendowych w celu przetworzenia jest dość proste.

Dzięki wiedzy z tego samouczka powinieneś być w stanie wdrożyć złożone serwery proxy i systemy równoważenia obciążenia, dzięki elastyczności Nginx.

Oto kilka materiałów, które znajdziesz na naszym blogu które pomogą Ci lepiej zapoznać się z Nginx:

Udanego korzystania z komputera!

author

Pranay Kapgate

Autor · CloudSigma

Preslav Dobrev jest projektantem kreatywnym w CloudSigma, skupiającym się na spójnej tożsamości biznesowej przy wykorzystaniu tradycyjnych i innowacyjnych kanałów marketingowych. Biegle łączy wizję artystyczną ze strategicznym marketingiem, tworząc wywierające wpływ narracje marki.

Komentarze

Brak komentarzy. Bądź pierwszy.