Configuración de Nginx server_names_hash_max_size y server_names_hash_bucket_size

22

Estamos utilizando Nginx como un proxy inverso a Apache en un servicio que proporciona a cualquiera su propio sitio web. En la creación de la cuenta, el sistema crea un nuevo archivo nginx conf para el dominio con dos entradas, una para el puerto 80 y la otra para 443. Notamos que en cada 30 dominios, obtenemos el error:

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.

Con alrededor de 200 dominios y creciendo, hemos tenido que aumentar el tamaño de server_names_hash_max a 4112 y nos preocupa que esto no vaya a escalar bien. Estoy buscando entender cómo funcionan estas configuraciones y cuáles serían las configuraciones óptimas para garantizar que podamos crecer a miles de dominios utilizando este método.

Además, con ese tamaño de hash, nginx está comenzando a tardar segundos en recargarse, lo que hace que el sistema no esté disponible mientras se reinicia.

Aquí están las configuraciones generales (ejecutándose en el servidor 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;
}

(Debajo de los cifrados hay un par de configuraciones del sitio principal y un catch all):

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

(Y un archivo de configuración de usuario de muestra)

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

¡Cualquier ayuda y dirección es muy apreciada!

jasonspalace
fuente

Respuestas:

14

La lista de servernombres que sirve nginx se almacena en una tabla hash para una búsqueda rápida . A medida que aumenta el número de entradas, debe aumentar el tamaño de la tabla hash y / o el número de depósitos hash en la tabla.

Dada la naturaleza de su configuración, no se me ocurre ninguna forma de reducir fácilmente la cantidad de servernombres que está almacenando en la tabla. Sin embargo, sugeriré que no "reinicie" nginx, sino que simplemente haga que vuelva a cargar su configuración. Por ejemplo:

service nginx reload
Michael Hampton
fuente
Eso es genial para la última parte de la pregunta, gracias. Entonces, ¿debería preocuparme que server_names_hash_max_size esté en algún lugar alrededor de 20000 para llegar a 10000 dominios?
jasonspalace
Solo es un problema cuando reinicia nginx. Como dije, en su reloadlugar siempre que sea posible para evitar el problema.
Michael Hampton
23

Solo algunos detalles técnicos que cavé forman el código fuente:

  • La recomendación general sería mantener ambos valores lo más pequeños posible.
  • Si nginx se queja, aumente max_sizeprimero siempre que se queje. Si el número excede un número grande (32769 por ejemplo), aumente bucket_sizea múltiplo del valor predeterminado en su plataforma siempre que se queje. Si ya no se queja, disminuya de max_sizenuevo siempre que no se queje. Ahora tiene la mejor configuración para su conjunto de nombres de servidor (cada conjunto de nombres de servidor puede necesitar una configuración diferente).
  • Más grande max_sizesignifica más memoria consumida (una vez por trabajador o servidor, comente si lo sabe).
  • Más grande bucket_sizesignifica más ciclos de CPU (para cada búsqueda de nombre de dominio) y más transferencias de la memoria principal al caché.
  • max_sizeno está relacionado directamente con el número de nombres de servidor, si el número de servidores se duplica, es posible que deba aumentar max_size10 veces o incluso más para evitar colisiones. Si no puedes evitarlos, tienes que aumentar bucket_size.
  • bucket_size se dice que se incrementa a la siguiente potencia de dos, desde el código fuente, yo juzgaría que debería ser suficiente para convertirlo en múltiplo del valor predeterminado, esto debería mantener las transferencias al caché óptimas.
  • El nombre de dominio promedio debe caber en 32 bytes incluso con la sobrecarga de la matriz hash. Si aumenta bucket_sizea 512 bytes, acomodaría 16 nombres de dominio con una clave hash en colisión. Esto no es algo que desee, si se produce una colisión, se busca linealmente . Desea tener la menor cantidad de colisiones posible.
  • Si tiene max_size menos de 10000 y es pequeño bucket_size, puede encontrar un largo tiempo de carga porque nginx intentaría encontrar el tamaño de hash óptimo en un bucle.
  • Si tiene max_sizemás de 10000, se realizarán "solo" 1000 bucles antes de que se queje.
brablc
fuente
Esta es una gran información; Gracias por la investigación y redacción.
womble
@brablc Tengo curiosidad por saber cómo llegaste a 32769, por ejemplo. ¿Dónde se puede ver cuál es el tamaño actual del montón?
Uhl Hosting
La memoria ocupada sería max_size * bucket_size (pero no sé si es compartida o por trabajador). Tenía 8000 nombres de servidor y 32769 ya se sentía demasiado alto. Pero si tiene mucha memoria, es posible que desee ir más alto.
brablc
4

Aumente la configuración "server_names_hash_bucket_size" dentro de su nginx.conf.

Lo tenía 64 y cambié a 128.

Problema resuelto.

Pedro Alvares
fuente
2

@Michael Hampton tiene toda la razón con su respuesta. Esta tabla hash se construye y compila durante el reinicio o la recarga y luego se ejecuta muy rápido. Supongo que esta tabla hash podría crecer mucho más sin degradar el rendimiento notable. Pero sugeriría usar un tamaño que sea potencia de dos, como 4096, debido a la naturaleza del código C.

Grillete de carne
fuente
Potencia de dos con qué base, ¿es correcto crecer en múltiplos del valor predeterminado de 512?
jasonspalace
Si, absolutamente.
Fleshgrinder
1

No estoy 100% seguro en su caso, pero recibí la misma advertencia porque estaba llamando proxy_set_header para X-Fordered-Proto dos veces:

proxy_set_header X-Forwarded-Proto ...;

Esto estaba sucediendo porque estaba incluyendo proxy_params, y contiene esta línea entre otras:

proxy_set_header X-Forwarded-Proto $scheme;

Al eliminar esa línea de la configuración de mi sitio, la advertencia desapareció.

TGO
fuente
1
Consejos de $$$, gracias.
sjas
-2

Cambio

proxy_set_header X-Forwarded-For $remote_addr;

a

proxy_set_header X-Real-IP $remote_addr;

javi
fuente