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

22

Мы используем 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;
}

(И пример пользовательского файла conf)

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

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

jasonspalace
источник

Ответы:

14

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

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

service nginx reload
Майкл Хэмптон
источник
Это здорово для последней части вопроса, спасибо. Так что я должен беспокоиться, что server_names_hash_max_size будет где-то около 20000, чтобы добраться до 10000 доменов?
jasonspalace
Это проблема только при перезапуске nginx. Как я уже сказал, reloadвместо этого по возможности избегайте проблемы.
Майкл Хэмптон
23

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

  • Общая рекомендация заключается в том, чтобы оба значения были как можно меньше.
  • Если nginx жалуется, увеличьте max_sizeсначала столько, сколько жалуется. Если число превышает какое-то большое число (например, 32769), увеличьте его bucket_sizeдо значения, кратного значению по умолчанию, на вашей платформе, пока она будет жаловаться. Если он больше не жалуется, уменьшите max_sizeего до тех пор, пока он не будет жаловаться. Теперь у вас есть лучшая настройка для вашего набора имен серверов (каждый набор имен серверов может нуждаться в другой настройке).
  • Большие max_sizeсредства потребляются больше памяти (один раз на одного работника или на сервере, пожалуйста , комментарий , если вы знаете).
  • Большие bucket_sizeозначает больше циклов процессора (для каждого доменного имени поиска) и больше переводов из основной памяти в кэш - памяти.
  • max_sizeне связано с количеством server_names напрямую, если количество серверов удваивается, вам может потребоваться увеличить его в max_size10 или даже больше, чтобы избежать коллизий. Если вы не можете избежать их, вы должны увеличить bucket_size.
  • bucket_size Говорят, что он будет увеличен до следующей степени двух, из исходного кода, я бы сказал, этого должно быть достаточно, чтобы сделать его кратным значению по умолчанию, это должно поддерживать оптимальную передачу в кэш.
  • Среднее доменное имя должно умещаться в 32 байта, даже с учетом издержек хеш-массива. Если вы увеличите bucket_sizeдо 512 байт, он будет содержать 16 доменных имен с коллизирующим хеш-ключом. Это не то, что вы хотите, если происходит столкновение, он ищет линейно . Вы хотите иметь как можно меньше столкновений.
  • Если у вас max_size меньше 10000 и меньше bucket_size, вы можете столкнуться с длительным временем загрузки, потому что nginx попытается найти оптимальный размер хеша в цикле.
  • Если у вас max_sizeбольше 10000, будет выполнено «только» 1000 циклов, прежде чем он будет жаловаться.
brablc
источник
Это отличная информация; спасибо за исследование и рецензию.
womble
@brablc Мне любопытно, как ты попал на 32769, например. Где можно увидеть каков текущий размер кучи?
Уль Хостинг
Занятая память будет max_size * bucket_size (но я не знаю, является ли она общей или для одного рабочего). У меня было 8000 имен серверов и 32769 чувствовал себя уже слишком высоко. Но если у вас много памяти, вы можете пойти выше.
Brablc
4

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

У меня было 64 и изменилось на 128.

Проблема решена.

Педро Альварес
источник
2

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

Fleshgrinder
источник
Степень двойки с какой базой, это правильно, чтобы расти в кратных по умолчанию 512?
jasonspalace
Да, конечно.
Флешгриндер
1

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

proxy_set_header X-Forwarded-Proto ...;

Это происходило потому, что я включал proxy_params, и он содержит следующую строку:

proxy_set_header X-Forwarded-Proto $scheme;

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

TGO
источник
1
реальный совет $$$, спасибо.
sjas
-2

+ Изменить

proxy_set_header X-Forwarded-For $remote_addr;

в

proxy_set_header X-Real-IP $remote_addr;

Javi
источник