Configuração do Nginx server_names_hash_max_size e server_names_hash_bucket_size

22

Estamos usando o Nginx como um proxy reverso para o Apache em um serviço que fornece a qualquer um o seu próprio site. Na criação da conta, o sistema cria um novo arquivo conf nginx para o domínio com duas entradas, uma para a porta 80 e a outra para 443. Observamos que em cada 30 domínios, obtemos o erro:

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.

Com cerca de 200 domínios em crescimento, tivemos que aumentar o tamanho de server_names_hash_max para 4112 e estamos preocupados com isso não vai escalar bem. Estou procurando entender como essas configurações funcionam e quais seriam as configurações ideais para garantir que possamos crescer para milhares de domínios usando esse método.

Além disso, nesse tamanho de hash, o nginx está começando a levar alguns segundos para recarregar, o que está causando a indisponibilidade do sistema durante a reinicialização.

Aqui estão as configurações gerais (em execução no 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;
}

(Abaixo das cifras, há algumas configurações principais do site e uma captura geral):

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

(E um exemplo de arquivo conf de usuário)

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

Qualquer ajuda e direção é muito apreciada !!

jasonspalace
fonte

Respostas:

14

A lista de servernomes que o nginx serve é armazenada em uma tabela de hash para pesquisa rápida . À medida que você aumenta o número de entradas, é necessário aumentar o tamanho da tabela de hash e / ou o número de buckets de hash na tabela.

Dada a natureza da sua configuração, não consigo pensar em nenhuma maneira de reduzir facilmente o número de servernomes que você está armazenando na tabela. Sugerirei, no entanto, que você não "reinicie" o nginx, mas simplesmente faça com que ele recarregue sua configuração. Por exemplo:

service nginx reload
Michael Hampton
fonte
Isso é ótimo para a última parte da pergunta, obrigado. Então, devo me preocupar que o server_names_hash_max_size esteja em torno de 20000 para chegar a 10000 domínios?
Jasonspalace 22/08/12
É apenas um problema quando você reinicia o nginx. Como eu disse, reloadem vez disso , sempre que possível, para evitar o problema.
Michael Hampton
23

Apenas alguns detalhes técnicos que eu cavei do código fonte:

  • A recomendação geral seria manter os dois valores o menor possível.
  • Se o nginx reclamar, aumente max_sizeprimeiro, desde que reclama. Se o número exceder um número grande (32769, por exemplo), aumente bucket_sizepara múltiplos do valor padrão em sua plataforma, desde que se queixe. Se já não se queixar, diminua de max_sizevolta, desde que não se queixe. Agora você tem a melhor configuração para o seu conjunto de nomes de servidores (cada conjunto de server_names pode precisar de uma configuração diferente).
  • Maior max_sizesignifica mais memória consumida (uma vez por trabalhador ou servidor, por favor, comente se você souber).
  • Maior bucket_sizesignifica mais ciclos de CPU (para cada pesquisa de nome de domínio) e mais transferências da memória principal para o cache.
  • max_sizenão está diretamente relacionado ao número de nomes de servidor, se o número de servidores dobrar, talvez seja necessário aumentar max_size10 vezes ou mais para evitar colisões. Se você não pode evitá-los, precisa aumentar bucket_size.
  • bucket_size é dito que foi aumentado para a próxima potência de dois, do código-fonte que eu julgaria que deveria ser suficiente para torná-lo múltiplo do valor padrão, isso deve manter as transferências para o cache ideal.
  • O nome médio do domínio deve caber em 32 bytes, mesmo com a sobrecarga da matriz de hash. Se você aumentar bucket_sizepara 512 bytes, ele acomodará 16 nomes de domínio com uma chave de hash em colisão. Isso não é algo que você deseja, se ocorrer uma colisão, ela procurará linearmente . Você deseja ter o mínimo de colisões possível.
  • Se você tem max_size menos de 10.000 e pequenos bucket_size, pode passar por um longo tempo de carregamento, porque o nginx tentaria encontrar o tamanho ideal de hash em um loop.
  • Se você tiver max_sizemais de 10000, haverá "apenas" 1000 loops executados antes da reclamação.
brablc
fonte
Esta é uma ótima informação; obrigado pela pesquisa e redação.
Womble
@brablc Estou curioso para saber como você chegou a 32769, por exemplo. Onde podemos ver qual é o tamanho atual da pilha?
Uhl Hosting
A memória ocupada seria max_size * bucket_size (mas não sei se é compartilhada ou por trabalhador). Eu tinha 8000 nomes de servidores e 32769 já parecia muito alto. Mas se você tem muita memória, pode querer ir mais alto.
Br
4

Aumente a configuração "server_names_hash_bucket_size" dentro do seu nginx.conf.

Eu tinha 64 e mudei para 128.

Problema resolvido.

Pedro Alvares
fonte
2

@ Michael Hampton está absolutamente certo com sua resposta. Essa tabela de hash é construída e compilada durante a reinicialização ou recarregamento e, posteriormente, é executada muito rapidamente. Eu acho que essa tabela de hash poderia crescer muito mais sem degradar o desempenho perceptível. Mas eu sugiro usar um tamanho que é o poder de dois, como 4096, devido à natureza do código C.

Triturador de Carne
fonte
Potência de dois com qual base, é correto crescer em múltiplos do padrão de 512?
precisa saber é o seguinte
Sim absolutamente.
Fleshgrinder 23/08/12
1

Não tenho 100% de certeza no seu caso, mas recebi o mesmo aviso porque estava chamando proxy_set_header para X-Forwarded-Proto duas vezes:

proxy_set_header X-Forwarded-Proto ...;

Isso estava acontecendo porque eu estava incluindo proxy_params, e ele contém essa linha entre outras:

proxy_set_header X-Forwarded-Proto $scheme;

A remoção dessa linha da configuração do meu site fez o aviso desaparecer.

TGO
fonte
11
conselhos reais de $$$, obrigado.
sjas 05/07
-2

mudança

proxy_set_header X-Forwarded-For $remote_addr;

para

proxy_set_header X-Real-IP $remote_addr;

javi
fonte