Ustawienie Nginx server_names_hash_max_size i server_names_hash_bucket_size

22

Używamy Nginx jako odwrotnego proxy do Apache w usłudze, która daje każdemu własną stronę internetową. Podczas tworzenia konta system tworzy nowy plik conf nginx dla domeny z dwoma wpisami, jeden dla portu 80, a drugi dla 443. Zauważamy, że przy każdych 30 domenach pojawia się błąd:

Restarting nginx: nginx: [emerg] could not build the server_names_hash, 
you should increase either server_names_hash_max_size: 256 
or server_names_hash_bucket_size: 64.

Przy około 200 domenach rośnie i musimy zwiększyć rozmiar server_names_hash_max do 4112 i obawiamy się, że to nie będzie dobrze skalować. Chcę zrozumieć, w jaki sposób działają te konfiguracje i jakie byłyby optymalne ustawienia, aby zapewnić nam możliwość rozwoju do tysięcy domen przy użyciu tej metody.

Ponadto przy tym rozmiarze skrótu nginx zaczyna ładować się sekundami, co powoduje, że system jest niedostępny podczas restartu.

Oto ogólne ustawienia (działające na serwerze Ubuntu 10.10 nginx / 1.0.4):

user www-data;
worker_processes 4;
pid /var/run/nginx.pid;

events {
    worker_connections 4096;
    # multi_accept on;
}

http {

    ##
    # Basic Settings
    ##

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 300;
    types_hash_max_size 2048;
    # server_tokens off;

    server_names_hash_bucket_size 64;
    # server_name_in_redirect off;
    # server_names_hash_max_size 2056;
    server_names_hash_max_size 4112;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # Logging Settings
    ##

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;
    gzip_disable "msie6";

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;

ssl_session_cache shared:SSL:10m;
ssl_ciphers ALL:!kEDH:-ADH:+HIGH:+MEDIUM:-LOW:+SSLv2:-EXP;
}

(Poniżej szyfrów jest kilka konfiguracji strony głównej i wszystkie łapie):

include /etc/user-nginx-confs/*;

server {
listen 80;
server_name .domain.com;
location / {
proxy_pass http://127.0.0.1:8011;
proxy_set_header host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-SystemUse-Header 111;
}
}

server {
listen 443 ssl;
server_name .suredone.com;
ssl_certificate /etc/apache2/sddbx/sdssl/suredone_chained.crt;
ssl_certificate_key /etc/apache2/sddbx/sdssl/suredone.key;
location / {
proxy_pass http://127.0.0.1:44311;
proxy_set_header host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-SystemUse-Header 111;
}
}

server {
listen 80 default_server;
listen 443 default_server ssl;
server_name _;
ssl_certificate /ssl/site_chained.crt;
ssl_certificate_key /ssl/site.key;
return 444;
}

(I przykładowy plik conf użytkownika)

server {
listen 80;
server_name username.domain.com;
location / {
proxy_pass http://127.0.0.1:8011;
proxy_set_header host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-SystemUse-Header 1111;
}
}

server {
listen 443 ssl;
server_name username.domain.com;
ssl_certificate /ssl/site_chained.crt;
ssl_certificate_key /ssl/site.key;
location / {
proxy_pass http://127.0.0.1:44311;
proxy_set_header host $http_host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-SystemUse-Header 1111;
}
}

Każda pomoc i wskazówki są mile widziane !!

jasonspalace
źródło

Odpowiedzi:

14

Lista servernazw obsługiwanych przez nginx jest przechowywana w tabeli skrótów w celu szybkiego wyszukiwania . Gdy zwiększasz liczbę wpisów, musisz zwiększyć rozmiar tabeli mieszającej i / lub liczbę segmentów mieszających w tabeli.

Biorąc pod uwagę naturę konfiguracji, nie mogę wymyślić żadnego sposobu, aby łatwo zmniejszyć liczbę servernazw przechowywanych w tabeli. Zasugeruję jednak, abyś nie „restartował” nginx, ale po prostu kazał mu ponownie załadować swoją konfigurację. Na przykład:

service nginx reload
Michael Hampton
źródło
To świetnie w drugiej części pytania, dzięki. Czy powinienem się martwić, że server_names_hash_max_size będzie gdzieś około 20000, aby dostać się do 10000 domen?
jasonspalace
To tylko problem po ponownym uruchomieniu nginx. Jak powiedziałem, reloadzamiast tego, gdy to możliwe, aby uniknąć problemu.
Michael Hampton
23

Po prostu kilka szczegółów technicznych, które wykopałem z kodu źródłowego:

  • Ogólne zalecenie byłoby, aby obie wartości były jak najmniejsze.
  • Jeśli nginx narzeka, max_sizenajpierw rośnie, o ile narzeka. Jeśli liczba przekroczy pewną dużą liczbę (na przykład 32769), zwiększ ją bucket_sizedo wielokrotności wartości domyślnej na swojej platformie, o ile narzeka. Jeśli już nie narzeka, zmniejsz max_sizesię, dopóki nie narzeka. Teraz masz najlepszą konfigurację zestawu nazw serwerów (każdy zestaw nazw serwerów może wymagać innej konfiguracji).
  • Większy max_sizeoznacza więcej pamięci (raz na pracownika lub serwer, proszę o komentarz, jeśli wiesz).
  • Większy bucket_sizeoznacza więcej cykli procesora (dla każdego wyszukiwania nazwy domeny) i więcej transferów z pamięci głównej do pamięci podręcznej.
  • max_sizenie ma bezpośredniego związku z liczbą nazw serwerów, jeśli liczba serwerów się podwoi, może być konieczne zwiększenie max_size10 lub nawet więcej razy, aby uniknąć kolizji. Jeśli nie możesz ich uniknąć, musisz zwiększyć bucket_size.
  • bucket_size mówi się, że zostanie zwiększony do następnej potęgi dwóch, z kodu źródłowego uważam, że powinien on wystarczyć do wielokrotności wartości domyślnej, co powinno utrzymać transfery do pamięci podręcznej optymalnie.
  • Średnia nazwa domeny powinna zmieścić się w 32 bajtach, nawet z narzutem tablicy mieszającej. Jeśli zwiększysz bucket_sizedo 512 bajtów, pomieści 16 nazw domen z kolidującym kluczem skrótu. Nie jest to coś, czego chcesz, jeśli zdarzy się kolizja, przeszukuje ona liniowo . Chcesz mieć jak najmniej kolizji.
  • Jeśli masz max_size mniej niż 10000 i mały bucket_size, możesz natknąć się na długi czas ładowania, ponieważ nginx spróbuje znaleźć optymalny rozmiar skrótu w pętli.
  • Jeśli masz max_sizewięcej niż 10000, wykona się „tylko” 1000 pętli, zanim będzie narzekać.
brablc
źródło
To jest świetna informacja; dzięki za badania i napisanie.
womble
@brablc Jestem ciekawy, jak na przykład dotarłeś do 32769. Gdzie można zobaczyć jaki jest obecny rozmiar sterty?
Uhl Hosting
Zajęta pamięć to max_size * bucket_size (ale nie wiem, czy jest współużytkowana, czy na pracownika). Miałem 8000 nazw serwerów i 32769 czułem się już za wysoko. Ale jeśli masz dużo pamięci, możesz chcieć pójść wyżej.
brablc
4

Zwiększ konfigurację „server_names_hash_bucket_size” w swoim pliku nginx.conf.

Miałem go 64 i zmieniłem na 128.

Problem rozwiązany.

Pedro Alvares
źródło
2

@Michael Hampton ma absolutną rację ze swoją odpowiedzią. Ta tabela skrótów jest konstruowana i kompilowana podczas ponownego uruchamiania lub przeładowywania, a następnie działa bardzo szybko. Wydaje mi się, że ta tabela skrótów mogłaby urosnąć o wiele więcej bez zauważalnego obniżenia wydajności. Ale sugerowałbym użycie rozmiaru, który jest potęgą dwóch, jak 4096, ze względu na naturę kodu C.

Fleshgrinder
źródło
Potęga dwóch przy jakiej podstawie, czy poprawne jest powiększanie się do wielokrotności domyślnej 512?
jasonspalace
Tak, absolutnie.
Fleshgrinder
1

W twoim przypadku nie jestem w 100% pewien, ale otrzymałem to samo ostrzeżenie, ponieważ dwukrotnie dzwoniłem do proxy_set_header dla X-Forwarded-Proto:

proxy_set_header X-Forwarded-Proto ...;

Działo się tak, ponieważ dołączałem proxy_params i zawiera on między innymi następujący wiersz:

proxy_set_header X-Forwarded-Proto $scheme;

Usunięcie tego wiersza z konfiguracji mojej witryny spowodowało, że ostrzeżenie zniknęło.

TGO
źródło
1
prawdziwe $$$ porady, dzięki.
sjas
-2

Zmiana

proxy_set_header X-Forwarded-For $remote_addr;

do

proxy_set_header X-Real-IP $remote_addr;

javi
źródło