Назад | Перейти на главную страницу

Настройка Nginx server_names_hash_max_size и server_names_hash_bucket_size

Мы используем Nginx в качестве обратного прокси для Apache в сервисе, который предоставляет каждому свой собственный веб-сайт. При создании учетной записи система создает новый файл конфигурации nginx для домена с двумя записями, одна для порта 80, другая для 443. Мы замечаем, что примерно через каждые 30 доменов мы получаем ошибку:

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.

Приблизительно с 200 доменами и ростом, нам пришлось увеличить размер server_names_hash_max до 4112 и обеспокоены тем, что это не будет хорошо масштабироваться. Я хочу понять, как работают эти конфигурации и какие будут оптимальные настройки, чтобы обеспечить возможность роста до тысяч доменов с помощью этого метода.

Кроме того, при таком размере хэша nginx начинает занимать секунды для перезагрузки, что приводит к недоступности системы во время перезапуска.

Вот общие настройки (работает на сервере 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;
}

(Ниже шифров - пара основных конфигураций сайта и все):

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

(И образец файла конфигурации пользователя)

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

Любая помощь и направление приветствуются!

Просто некоторые технические детали, которые я извлек из исходного кода:

  • Общая рекомендация - сохранить оба значения как можно меньшими.
  • Если nginx жалуется на увеличение max_size сначала пока жалуется. Если число превышает какое-то большое число (например, 32769), увеличьте bucket_size до кратного значения по умолчанию на вашей платформе, пока он жалуется. Если больше не жалуется, уменьшите max_size назад пока не жалуется. Теперь у вас есть лучшая настройка для вашего набора имен серверов (для каждого набора server_names может потребоваться другая настройка).
  • Больше max_size означает больше потребляемой памяти (один раз на рабочий или сервер, прокомментируйте, если знаете).
  • Больше bucket_size означает больше циклов ЦП (для каждого поиска доменного имени) и больше передач из основной памяти в кеш.
  • max_size не связано напрямую с количеством server_names, если количество серверов удваивается, вам может потребоваться увеличить max_size 10 раз и даже больше, чтобы избежать столкновений. Если вы не можете их избежать, вам нужно увеличить bucket_size.
  • bucket_size считается, что увеличивается до следующей степени двойки, исходя из исходного кода, я бы решил, что этого должно быть достаточно, чтобы сделать его кратным значению по умолчанию, это должно поддерживать оптимальные переводы в кеш.
  • Среднее доменное имя должно умещаться в 32 байта даже с накладными расходами на массив хешей. Если вы увеличите bucket_size до 512 байт, он вмещает 16 доменных имен с конфликтующим хеш-ключом. Это не то, что вам нужно, если произойдет столкновение он ищет линейно. Вы хотите, чтобы столкновений было как можно меньше.
  • Если у вас есть max_size менее 10000 и маленький bucket_size, вы можете столкнуться с длительным временем загрузки, потому что nginx будет пытаться найти оптимальный размер хэша в цикле.
  • Если у вас есть max_size больше 10000, будет выполнено "только" 1000 циклов, прежде чем он будет жаловаться.

Список server имена, которые обслуживает nginx, это хранится в хеш-таблице для быстрого поиска. По мере увеличения количества записей необходимо увеличивать размер хеш-таблицы и / или количество хеш-сегментов в таблице.

Учитывая характер вашей настройки, я не могу придумать, как вы могли бы легко уменьшить количество server имена, которые вы храните в таблице. Однако я предлагаю вам не «перезапускать» nginx, а просто перезагрузить его конфигурацию. Например:

service nginx reload

Увеличьте конфигурацию server_names_hash_bucket_size внутри вашего nginx.conf.

У меня было 64, поменял на 128.

Задача решена.

@ Майкл Хэмптон абсолютно прав со своим ответом. Эта хеш-таблица создается и компилируется во время перезапуска или перезагрузки, а затем работает очень быстро. Я предполагаю, что эта хеш-таблица может значительно увеличиться без заметного снижения производительности. Но я бы предложил использовать размер, равный степени двойки, например 4096, из-за природы кода C.

Я не уверен на 100% в вашем случае, но я получал такое же предупреждение, потому что дважды вызывал proxy_set_header для X-Forwarded-Proto:

proxy_set_header X-Forwarded-Proto ...;

Это произошло потому, что я включил proxy_params, и среди прочего он содержит эту строку:

proxy_set_header X-Forwarded-Proto $scheme;

Удаление этой строки из конфигурации моего сайта сняло предупреждение.

+ Изменить

proxy_set_header X-Forwarded-For $remote_addr;

к

proxy_set_header X-Real-IP $remote_addr;