Nginx Einstellung server_names_hash_max_size und server_names_hash_bucket_size

22

Wir verwenden Nginx als Reverse-Proxy für Apache in einem Service, der jedem seine eigene Website zur Verfügung stellt. Bei der Kontoerstellung erstellt das System eine neue Nginx-Konfigurationsdatei für die Domäne mit zwei Einträgen, einen für Port 80 und einen für 443. Wir stellen fest, dass bei etwa 30 Domänen der folgende Fehler auftritt:

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.

Mit rund 200 Domains und zunehmender Größe mussten wir die Größe von server_names_hash_max auf 4112 erhöhen und befürchten, dass dies nicht gut skaliert werden kann. Ich möchte verstehen, wie diese Konfigurationen funktionieren und wie die optimalen Einstellungen aussehen, um sicherzustellen, dass wir mit dieser Methode auf Tausende von Domänen anwachsen können.

Ab dieser Hash-Größe dauert es außerdem einige Sekunden, bis Nginx wieder geladen ist. Dies führt dazu, dass das System beim Neustart nicht mehr verfügbar ist.

Hier sind die allgemeinen Einstellungen (unter Ubuntu Server 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;
}

(Unter den Chiffren befinden sich einige Haupt-Site-Konfigurationen und ein Haken an alle):

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;
}

(Und eine Beispiel-Benutzer-Conf-Datei)

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;
}
}

Jede Hilfe und Anleitung wird sehr geschätzt !!

Jasonspalace
quelle

Antworten:

14

Die Liste der serverNamen, die Nginx bedient, wird in einer Hash-Tabelle für die schnelle Suche gespeichert . Wenn Sie die Anzahl der Einträge erhöhen, müssen Sie die Größe der Hash-Tabelle und / oder die Anzahl der Hash-Buckets in der Tabelle erhöhen.

Angesichts der Art Ihres Setups kann ich Ihnen keine Möglichkeit vorstellen, die Anzahl der serverNamen, die Sie in der Tabelle speichern, auf einfache Weise zu reduzieren . Ich werde jedoch vorschlagen, dass Sie nginx nicht "neu starten", sondern einfach seine Konfiguration neu laden lassen. Zum Beispiel:

service nginx reload
Michael Hampton
quelle
Das ist großartig für den letzten Teil der Frage, danke. Sollte ich mir also Sorgen machen, dass der Wert für server_names_hash_max_size etwa 20000 beträgt, um auf 10000 Domains zu gelangen?
Jasonspalace
Es ist nur ein Problem, wenn Sie Nginx neu starten. Wie gesagt, reloadstattdessen, wann immer möglich, um das Problem zu vermeiden.
Michael Hampton
23

Nur ein paar technische Details, die ich für den Quellcode ausgegraben habe:

  • Die generelle Empfehlung wäre, beide Werte so klein wie möglich zu halten.
  • Wenn Nginx sich beschwert, erhöhen Sie max_sizezuerst, solange es sich beschwert. Wenn die Zahl eine große Zahl überschreitet (z. B. 32769), erhöhen Sie sie bucket_sizeauf ein Vielfaches des Standardwerts auf Ihrer Plattform, solange Sie sich beschweren. Wenn es sich nicht mehr beschwert, nehmen Sie max_sizezurück, solange es sich nicht beschwert. Jetzt haben Sie das beste Setup für Ihren Satz von Servernamen (jeder Satz von Servernamen erfordert möglicherweise ein anderes Setup).
  • Größer max_sizebedeutet, dass mehr Speicher verbraucht wird (einmal pro Worker oder Server, bitte kommentieren, wenn Sie es wissen).
  • Größer bucket_sizebedeutet mehr CPU-Zyklen (für jede Domainnamen-Suche) und mehr Übertragungen vom Hauptspeicher in den Cache.
  • max_sizebezieht sich nicht direkt auf die Anzahl der Servernamen. Wenn sich die Anzahl der Server verdoppelt, müssen Sie möglicherweise die Anzahl um das max_sizeZehnfache oder sogar mehr erhöhen , um Kollisionen zu vermeiden. Wenn Sie sie nicht vermeiden können, müssen Sie erhöhen bucket_size.
  • bucket_size soll auf die nächste Potenz von zwei erhöht werden, aus dem Quellcode würde ich beurteilen, dass es ausreichen sollte, um es ein Vielfaches des Standardwerts zu machen, dies sollte die Übertragungen in den Cache optimal halten.
  • Der durchschnittliche Domänenname sollte auch mit Hash-Array-Overhead in 32 Byte passen. Wenn Sie bucket_sizeauf 512 Byte erhöhen , können 16 Domänennamen mit kollidierendem Hash-Schlüssel verwendet werden. Dies ist nicht das, was Sie wollen, wenn es zu einer Kollision kommt , wird linear gesucht . Sie möchten so wenig Kollisionen wie möglich haben.
  • Wenn Sie max_size weniger als 10000 und kleiner haben bucket_size, können Sie auf lange Ladezeiten stoßen, da Nginx versuchen würde, die optimale Hash-Größe in einer Schleife zu finden.
  • Wenn Sie mehr max_sizeals 10000 haben, werden "nur" 1000 Schleifen ausgeführt, bevor sich jemand beschwert.
brablc
quelle
Das sind großartige Informationen. Vielen Dank für die Recherche und das Schreiben.
womble
@brablc Ich bin gespannt, wie du zum Beispiel auf 32769 gekommen bist. Wo kann man sehen, was die aktuelle Heap-Größe ist?
Uhl Hosting
Der belegte Speicher wäre max_size * bucket_size (aber ich weiß nicht, ob er gemeinsam genutzt wird oder pro Worker). Ich hatte 8000 Servernamen und fühlte mich 32769 schon zu hoch. Aber wenn Sie viel Gedächtnis haben, möchten Sie vielleicht höher gehen.
Brablc
4

Erhöhen Sie die Konfiguration "server_names_hash_bucket_size" in Ihrer nginx.conf.

Ich hatte es 64 und wechselte zu 128.

Problem gelöst.

Pedro Alvares
quelle
2

@Michael Hampton ist absolut richtig mit seiner Antwort. Diese Hash-Tabelle wird beim Neustart oder Neuladen erstellt und kompiliert und läuft danach sehr schnell. Ich schätze, diese Hash-Tabelle könnte viel größer werden, ohne die Leistung merklich zu beeinträchtigen. Aber ich würde vorschlagen, eine Größe zu verwenden, die Potenz von zwei ist, wie 4096, aufgrund der Natur des C-Codes.

Fleischwolf
quelle
Zweierpotenz auf welcher Basis? Ist es richtig, ein Vielfaches der Standardgröße von 512 zu erreichen?
Jasonspalace
Ja absolut.
Fleischwolf
1

Ich bin mir in Ihrem Fall nicht 100% sicher, habe aber dieselbe Warnung erhalten, weil ich zweimal proxy_set_header für X-Forwarded-Proto aufgerufen habe:

proxy_set_header X-Forwarded-Proto ...;

Dies geschah, weil ich proxy_params mit einbezog und diese Zeile unter anderem enthält:

proxy_set_header X-Forwarded-Proto $scheme;

Durch das Entfernen dieser Zeile aus der Konfiguration meiner Site wurde die Warnung ausgeblendet.

TGO
quelle
1
echte $$$ Beratung, danke.
Samstag,
-2

Veränderung

proxy_set_header X-Forwarded-For $remote_addr;

zu

proxy_set_header X-Real-IP $remote_addr;

javi
quelle