nginx 如何处理请求系列3-server_name指令

当Nginx收到请求后,Nginx分成两部分进行,包括server_name和URL,首先Nginx通过server_name匹配来确定使用哪个server块来处理请求。

分 析

当用户的访问通过网络与nginx建立连接后,nginx首先通过http协议里Request Headers中的Host字段来解析成server_name. 这里我们使用curl命令来查看。如果提示无该命令,centos可使用yum -y install curl 来安装。

[root@slave2 ~]# curl localhost -v         
* About to connect() to localhost port 80 (#0)
*   Trying ::1... Connection refused
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: nginx/1.12.2
< Date: Mon, 08 Jan 2018 09:43:50 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 17 Oct 2017 13:25:44 GMT
< Connection: keep-alive
< ETag: "59e604d8-264"
< Accept-Ranges: bytes
< 

* Connection #0 to host localhost left intact
* Closing connection #0 

这里注意

> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: localhost
> Accept: */*
>

nginx解析该请求,得到当前请求的server_name为localhost。当nginx启动时会加载所有的配置文件,并将配置文件中的server指令定义的块中的server_name加入到server_names_hash中,这里注意,如果没有定义 default_server会多加入一个server_name为default_server的server块。

我们来看如下nginx配置文件,省略部分无影响的配置。

server {
    listen      80;
    server_name 172.19.23.208;
}

server {
    listen      80;
    server_name test.com;

}

server {
    listen      808;
    server_name 172.19.23.208;
}

Note 对于test.com,你可能需要通过指定hosts文件来使该域名访问到nginx。

[root@slave2 ~]# curl 172.19.23.208:808 -v
* About to connect() to 172.19.23.208 port 808 (#0)
*   Trying 172.19.23.208... connected
* Connected to 172.19.23.208 (172.19.23.208) port 808 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.16.2.3 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
> Host: 172.19.23.208:808
> Accept: */*
> 
< HTTP/1.1 404 Not Found
< Server: nginx/1.12.2
< Date: Mon, 08 Jan 2018 10:03:39 GMT
< Content-Type: text/html
< Content-Length: 169
< Connection: keep-alive
< 

注意Host字段变成172.19.23.208:808,nginx解析它,server_name为172.19.23.208,port为808,port在server_name匹配前已使用,所以nginx会使用配置段

server {
	listen      808;
    server_name 172.19.23.208;
}

来处理该请求,至于请求后续的处理,后面来看。

这里要知道,nginx的server匹配是有优先级的,官方文档,这在host能匹配多个server块时尤其重要。 匹配原则如下

  1. exact name 精确名(eg "www.test.com","172.19.23.208")
  • longest wildcard name starting with an asterisk, e.g. “*.example.org” 星号开始的最长通配符名
  • longest wildcard name ending with an asterisk, e.g. “mail.*” 星号结束的最长通配符名
  • first matching regular expression (in order of appearance in a configuration file) 最先匹配的正则表达式名(除开星号开始和结束的正则表达式 eg, "~^(?<user>.+).example.net$")

性能优化

Exact names, 星号开始的最长通配符名,星号结束的最长通配符名在三个哈希表中,哈希表的尺寸在configuration phase进行了优化,这里有一点点性能不同, server_name按照域名来搜索的,所以exact names速度最快。注意.example.org储存在星号开始的最长通配符名的哈希表中。 正则表达式是串行测试,所以最慢,且不可扩展。

所以请尽可能使用exact name。example.org和www.example.org被访问得最频繁的,那么将它们明确的定义出来效果就会更好。

server {
    listen       80;
    server_name  example.org  www.example.org  *.example.org;
    ...
}

实际书写nginx配置文件时,尽量使用exact name作为server_name 这样一目了然,同时避免新手歧义,也带来性能提升。

这里有两个参数

server_names_hash_max_size server_name哈希表空间最大,等同于为python字典设置了最大key的个数。

server_names_hash_bucket_size server_name最大长度,等同于python字典string value的最大长度。

比如:

server {
	server_name too.long.server.name.example.org;
}

启动(或reload)提示

could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

处理:

http {
	server_names_hash_bucket_size  64;
	...
}

另一个我们有个托管的虚拟主机,有大量的server_name需要引入时:

could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

先尝试设置server_names_hash_max_size的值差不多等于哈希表key的总数。如果没用,或者服务器启动非常缓慢,再提高server_names_hash_bucket_size的值。

如果只为一个监听端口配置了唯一的主机,那么nginx就完全不会测试虚拟主机名了(也不会为监听端口建立哈希表)。但有一个例外,如果定义的虚拟主机名是一个含有捕获组的正则表达式,这时nginx就不得不执行这个表达式以得到捕获组。

当server_name匹配完成后,便会进行nginx的phase handler,即处理阶段。

猜你喜欢

转载自my.oschina.net/monkeyzhu/blog/1649580