Nginx设置server_names_hash_max_size和server_names_hash_bucket_size


22

我们正在使用Nginx作为Apache的反向代理,该服务可以为任何人提供自己的网站。在创建帐户时,系统会为该域创建一个新的nginx conf文件,其中包含两个条目,一个条目用于端口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;
}
}

任何帮助和指示,不胜感激!

Answers:


14

servernginx服务的名称列表存储在哈希表中,用于快速查找。随着条目数量的增加,您必须增加哈希表的大小和/或表中哈希桶的数量。

鉴于设置的性质,我想不出任何办法来轻松减少server表中存储的名称数量。不过,我建议您不要“重新启动” nginx,而只是让它重新加载其配置。例如:

service nginx reload

对于问题的后半部分,这很好,谢谢。因此,我是否应该担心server_names_hash_max_size会在20000左右才能到达10000个域?
jasonspalace 2012年

重新启动nginx只是一个问题。正如我所说,reload应尽可能避免出现问题。
迈克尔·汉普顿

23

我从源代码中挖掘了一些技术细节:

  • 一般建议是使两个值都尽可能小。
  • max_size只要nginx抱怨,只要它抱怨就先增加。如果该数字超过某个大数字(例如32769),请增加bucket_size平台上默认值的倍数,只要它抱怨即可。如果不再抱怨,请减少max_size它,直到不再抱怨。现在,您已经为服务器名称集设置了最佳设置(每组server_names可能需要不同的设置)。
  • 更大max_size意味着更多的内存消耗(每台工作服务器或服务器一次,如果知道,请发表评论)。
  • 更大bucket_size意味着更多的CPU周期(用于每个域名查找)以及更多的从主内存到缓存的传输。
  • max_size与server_names的数量没有直接关系,如果服务器数量增加一倍,则可能需要增加max_size10倍甚至更多倍以避免冲突。如果无法避免它们,则必须增加bucket_size
  • bucket_size 据说要增加到2的下一个乘方,从源代码中,我认为将其设为默认值的倍数应该足够了,这应该使传输到高速缓存保持最佳状态。
  • 即使具有哈希数组开销,平均域名也应适合32个字节。如果增加到bucket_size512字节,它将使用冲突的哈希键容纳16个域名。这不是您想要的东西,如果发生碰撞,它将线性搜索。您希望冲突尽可能少。
  • 如果max_size 小于10000且小于bucket_size,则可能会遇到较长的加载时间,因为nginx会尝试在循环中找到最佳的哈希值。
  • 如果max_size大于10000,那么在抱怨之前将仅执行1000个循环。

这是很棒的信息;感谢您的研究和撰写。
womble

@brablc我很好奇例如您如何达到32769。在哪里可以看到当前堆大小是多少?
Uhl主办

占用的内存为max_size * bucket_size(但我不知道它是共享的还是每个工人的)。我有8000个服务器名称,并且32769感觉已经太高了。但是,如果您有很多内存,则可能需要更高的内存。
brablc


2

@迈克尔·汉普顿的回答绝对正确。该哈希表是在重新启动或重新加载期间构造和编译的,之后运行非常快。我猜这个哈希表可以增长很多,而不会降低性能。但由于C代码的性质,我建议使用2的幂,例如4096。


以2为底的幂是多少,以默认值512的倍数增长是否正确?
jasonspalace 2012年

是的,一点没错。
Fleshgrinder

1

对于您的情况,我不是100%肯定的,但是由于收到两次X-Forwarded-Proto的proxy_set_header的消息,我得到了同样的警告:

proxy_set_header X-Forwarded-Proto ...;

发生这种情况是因为我包括了proxy_params,并且其中包括以下这一行:

proxy_set_header X-Forwarded-Proto $scheme;

从我的站点配置中删除该行后,警告消失了。


1
真正的$$$建议,谢谢。
sjas

-2

更改

proxy_set_header X-Forwarded-For $remote_addr;

proxy_set_header X-Real-IP $remote_addr;

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.