Мы используем 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;
}
}
Любая помощь и направление приветствуются!
Просто некоторые технические детали, которые я извлек из исходного кода:
max_size
сначала пока жалуется. Если число превышает какое-то большое число (например, 32769), увеличьте bucket_size
до кратного значения по умолчанию на вашей платформе, пока он жалуется. Если больше не жалуется, уменьшите max_size
назад пока не жалуется. Теперь у вас есть лучшая настройка для вашего набора имен серверов (для каждого набора server_names может потребоваться другая настройка).max_size
означает больше потребляемой памяти (один раз на рабочий или сервер, прокомментируйте, если знаете).bucket_size
означает больше циклов ЦП (для каждого поиска доменного имени) и больше передач из основной памяти в кеш.max_size
не связано напрямую с количеством server_names, если количество серверов удваивается, вам может потребоваться увеличить max_size
10 раз и даже больше, чтобы избежать столкновений. Если вы не можете их избежать, вам нужно увеличить bucket_size
.bucket_size
считается, что увеличивается до следующей степени двойки, исходя из исходного кода, я бы решил, что этого должно быть достаточно, чтобы сделать его кратным значению по умолчанию, это должно поддерживать оптимальные переводы в кеш.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;