2.4 用HTTP核心模块配置一个静态Web服务器
静态Web服务器的主要功能由ngx_http_core_module模块(HTTP框架的主要成员)实现,当然,一个完整的静态Web服务器还有许多功能是由其他的HTTP模块实现的。本节主要讨论如何配置一个包含基本功能的静态Web服务器,文中会完整地说明ngx_http_core_module模块提供的配置项及变量的用法,但不会过多说明其他HTTP模块的配置项。在阅读完本节内容后,读者应当可以通过简单的查询相关模块(如ngx_http_gzip_filter_module、ngx_http_image_filter_module等)的配置项说明,方便地在nginx.conf配置文件中加入新的配置项,从而实现更多的Web服务器功能。
除了2.3节提到的基本配置项外,一个典型的静态Web服务器还会包含多个server块和location块,例如:
http { gzip on; upstream { … } … server { listen localhost:80; … location /webstatic { if … { … } root /opt/webresource; … } location ~* .(jpg|jpeg|png|jpe|gif)$ { … } } server { … } }
所有的HTTP配置项都必须直属于http块、server块、location块、upstream块或if块等(HTTP配置项自然必须全部在http{}块之内,这里的“直属于”是指配置项直接所属的大括号对应的配置块),同时,在描述每个配置项的功能时,会说明它可以在上述的哪个块中存在,因为有些配置项可以任意地出现在某一个块中,而有些配置项只能出现在特定的块中,在第4章介绍自定义配置项的读取时,相信读者就会体会到这种设计思路。
Nginx为配置一个完整的静态Web服务器提供了非常多的功能,下面会把这些配置项分为以下8类进行详述:虚拟主机与请求的分发、文件路径的定义、内存及磁盘资源的分配、网络连接的设置、MIME类型的设置、对客户端请求的限制、文件操作的优化、对客户端请求的特殊处理。这种划分只是为了帮助大家从功能上理解这些配置项。
在这之后会列出ngx_http_core_module模块提供的变量,以及简单说明它们的意义。
2.4.1 虚拟主机与请求的分发
由于IP地址的数量有限,因此经常存在多个主机域名对应着同一个IP地址的情况,这时在nginx.conf中就可以按照server_name(对应用户请求中的主机域名)并通过server块来定义虚拟主机,每个server块就是一个虚拟主机,它只处理与之相对应的主机域名请求。这样,一台服务器上的Nginx就能以不同的方式处理访问不同主机域名的HTTP请求了。
(1)监听端口
语法:listen address:port[default(deprecated in 0.8.21)|default_server|[backlog=num|rcvbuf=size|sndbuf=size|accept_filter=filter|deferred|bind|ipv6only=[on|off]|ssl]];
默认:listen 80;
配置块:server
listen参数决定Nginx服务如何监听端口。在listen后可以只加IP地址、端口或主机名,非常灵活,例如:
listen 127.0.0.1:8000; listen 127.0.0.1; #注意:不加端口时,默认监听80端口 listen 8000; listen *:8000; listen localhost:8000;
如果服务器使用IPv6地址,那么可以这样使用:
listen [::]:8000; listen [fe80::1]; listen [:::a8c9:1234]:80;
在地址和端口后,还可以加上其他参数,例如:
listen 443 default_server ssl; listen 127.0.0.1 default_server accept_filter=dataready backlog=1024;
下面说明listen可用参数的意义。
❑ default:将所在的server块作为整个Web服务的默认server块。如果没有设置这个参数,那么将会以在nginx.conf中找到的第一个server块作为默认server块。为什么需要默认虚拟主机呢?当一个请求无法匹配配置文件中的所有主机域名时,就会选用默认的虚拟主机(在11.3节介绍默认主机的使用)。
❑ default_server:同上。
❑ backlog=num:表示TCP中backlog队列的大小。默认为–1,表示不予设置。在TCP建立三次握手过程中,进程还没有开始处理监听句柄,这时backlog队列将会放置这些新连接。可如果backlog队列已满,还有新的客户端试图通过三次握手建立TCP连接,这时客户端将会建立连接失败。
❑ rcvbuf=size:设置监听句柄的SO_RCVBUF参数。
❑ sndbuf=size:设置监听句柄的SO_SNDBUF参数。
❑ accept_filter:设置accept过滤器,只对FreeBSD操作系统有用。
❑ deferred:在设置该参数后,若用户发起建立连接请求,并且完成了TCP的三次握手,内核也不会为了这次的连接调度worker进程来处理,只有用户真的发送请求数据时(内核已经在网卡中收到请求数据包),内核才会唤醒worker进程处理这个连接。这个参数适用于大并发的情况下,它减轻了worker进程的负担。当请求数据来临时,worker进程才会开始处理这个连接。只有确认上面所说的应用场景符合自己的业务需求时,才可以使用deferred配置。
❑ bind:绑定当前端口/地址对,如127.0.0.1:8000。只有同时对一个端口监听多个地址时才会生效。
❑ ssl:在当前监听的端口上建立的连接必须基于SSL协议。
(2)主机名称
语法:server_name name[...];
默认:server_name"";
配置块:server
server_name后可以跟多个主机名称,如server_name www.testweb.com、download.testweb.com;。
在开始处理一个HTTP请求时,Nginx会取出header头中的Host,与每个server中的server_name进行匹配,以此决定到底由哪一个server块来处理这个请求。有可能一个Host与多个server块中的server_name都匹配,这时就会根据匹配优先级来选择实际处理的server块。server_name与Host的匹配优先级如下:
1)首先选择所有字符串完全匹配的server_name,如www.testweb.com。
2)其次选择通配符在前面的server_name,如*.testweb.com。
3)再次选择通配符在后面的server_name,如www.testweb.*。
4)最后选择使用正则表达式才匹配的server_name,如~^\.testweb\.com$。
实际上,这个规则正是7.7节中介绍的带通配符散列表的实现依据,同时,在10.4节也介绍了虚拟主机配置的管理。如果Host与所有的server_name都不匹配,这时将会按下列顺序选择处理的server块。
1)优先选择在listen配置项后加入[default|default_server]的server块。
2)找到匹配listen端口的第一个server块。
如果server_name后跟着空字符串(如server_name"";),那么表示匹配没有Host这个HTTP头部的请求。
注意:Nginx正是使用server_name配置项针对特定Host域名的请求提供不同的服务,以此实现虚拟主机功能。
(3)server_names_hash_bucket_size
语法:server_names_hash_bucket_size size;
默认:server_names_hash_bucket_size 32|64|128;
配置块:http、server、location
为了提高快速寻找到相应server name的能力,Nginx使用散列表来存储server name。server_names_hash_bucket_size设置了每个散列桶占用的内存大小。
(4)server_names_hash_max_size
语法:server_names_hash_max_size size;
默认:server_names_hash_max_size 512;
配置块:http、server、location
server_names_hash_max_size会影响散列表的冲突率。server_names_hash_max_size越大,消耗的内存就越多,但散列key的冲突率则会降低,检索速度也更快。server_names_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能增高。
(5)重定向主机名称的处理
语法:server_name_in_redirect on|off;
默认:server_name_in_redirect on;
配置块:http、server或者location
该配置需要配合server_name使用。在使用on打开时,表示在重定向请求时会使用server_name里配置的第一个主机名代替原先请求中的Host头部,而使用off关闭时,表示在重定向请求时使用请求本身的Host头部。
(6)location
语法:location[=|~|~*|^~|@]/uri/{...}
配置块:server
location会尝试根据用户请求中的URI来匹配上面的/uri表达式,如果可以匹配,就选择location{}块中的配置来处理用户请求。当然,匹配方式是多样的,下面介绍location的匹配规则。
1)=表示把URI作为字符串,以便与参数中的uri做完全匹配。例如:
location = / { #只有当用户请求是/时,才会使用该location下的配置 … }
2)~表示匹配URI时是字母大小写敏感的。
3)~*表示匹配URI时忽略字母大小写问题。
4)^~表示匹配URI时只需要其前半部分与uri参数匹配即可。例如:
location ^~ /images/ { # 以/images/开始的请求都会匹配上 … }
5)@表示仅用于Nginx服务内部请求之间的重定向,带有@的location不直接处理用户请求。
当然,在uri参数里是可以用正则表达式的,例如:
location ~* \.(gif|jpg|jpeg)$ { # 匹配以.gif、.jpg、.jpeg结尾的请求 … }
注意,location是有顺序的,当一个请求有可能匹配多个location时,实际上这个请求会被第一个location处理。
在以上各种匹配方式中,都只能表达为“如果匹配...则...”。如果需要表达“如果不匹配...则...”,就很难直接做到。有一种解决方法是在最后一个location中使用/作为参数,它会匹配所有的HTTP请求,这样就可以表示如果不能匹配前面的所有location,则由“/”这个location处理。例如:
location / { # /可以匹配所有请求 … }
2.4.2 文件路径的定义
下面介绍一下文件路径的定义配置项。
(1)以root方式设置资源路径
语法:root path;
默认:root html;
配置块:http、server、location、if
例如,定义资源文件相对于HTTP请求的根目录。
location /download/ { root /opt/web/html/; }
在上面的配置中,如果有一个请求的URI是/download/index/test.html,那么Web服务器将会返回服务器上/opt/web/html/download/index/test.html文件的内容。
(2)以alias方式设置资源路径
语法:alias path;
配置块:location
alias也是用来设置文件资源路径的,它与root的不同点主要在于如何解读紧跟location后面的uri参数,这将会致使alias与root以不同的方式将用户请求映射到真正的磁盘文件上。例如,如果有一个请求的URI是/conf/nginx.conf,而用户实际想访问的文件在/usr/local/nginx/conf/nginx.conf,那么想要使用alias来进行设置的话,可以采用如下方式:
location /conf { alias /usr/local/nginx/conf/; }
如果用root设置,那么语句如下所示:
location /conf { root /usr/local/nginx/; }
使用alias时,在URI向实际文件路径的映射过程中,已经把location后配置的/conf这部分字符串丢弃掉,因此,/conf/nginx.conf请求将根据alias path映射为path/nginx.conf。root则不然,它会根据完整的URI请求来映射,因此,/conf/nginx.conf请求会根据root path映射为path/conf/nginx.conf。这也是root可以放置到http、server、location或if块中,而alias只能放置到location块中的原因。
alias后面还可以添加正则表达式,例如:
location ~ ^/test/(\w+)\.(\w+)$ { alias /usr/local/nginx/$2/$1.$2; }
这样,请求在访问/test/nginx.conf时,Nginx会返回/usr/local/nginx/conf/nginx.conf文件中的内容。
(3)访问首页
语法:index file...;
默认:index index.html;
配置块:http、server、location
有时,访问站点时的URI是/,这时一般是返回网站的首页,而这与root和alias都不同。这里用ngx_http_index_module模块提供的index配置实现。index后可以跟多个文件参数,Nginx将会按照顺序来访问这些文件,例如:
location / { root path; index /index.html /html/index.php /index.php; }
接收到请求后,Nginx首先会尝试访问path/index.php文件,如果可以访问,就直接返回文件内容结束请求,否则再试图返回path/html/index.php文件的内容,依此类推。
(4)根据HTTP返回码重定向页面
语法:error_page code[code...][=|=answer-code]uri|@named_location
配置块:http、server、location、if
当对于某个请求返回错误码时,如果匹配上了error_page中设置的code,则重定向到新的URI中。例如:
error_page 404 /404.html; error_page 502 503 504 /50x.html; error_page 403 http://example.com/forbidden.html; error_page 404 = @fetch;
注意,虽然重定向了URI,但返回的HTTP错误码还是与原来的相同。用户可以通过“=”来更改返回的错误码,例如:
error_page 404 =200 /empty.gif; error_page 404 =403 /forbidden.gif;
也可以不指定确切的返回错误码,而是由重定向后实际处理的真实结果来决定,这时,只要把“=”后面的错误码去掉即可,例如:
error_page 404 = /empty.gif;
如果不想修改URI,只是想让这样的请求重定向到另一个location中进行处理,那么可以这样设置:
location / ( error_page 404 @fallback; ) location @fallback ( proxy_pass http://backend; )
这样,返回404的请求会被反向代理到http://backend上游服务器中处理。
(5)是否允许递归使用error_page
语法:recursive_error_pages[on|off];
默认:recursive_error_pages off;
配置块:http、server、location
确定是否允许递归地定义error_page。
(6)try_files
语法:try_files path1[path2]uri;
配置块:server、location
try_files后要跟若干路径,如path1 path2...,而且最后必须要有uri参数,意义如下:尝试按照顺序访问每一个path,如果可以有效地读取,就直接向用户返回这个path对应的文件结束请求,否则继续向下访问。如果所有的path都找不到有效的文件,就重定向到最后的参数uri上。因此,最后这个参数uri必须存在,而且它应该是可以有效重定向的。例如:
try_files /system/maintenance.html $uri $uri/index.html $uri.html @other; location @other { proxy_pass http://backend; }
上面这段代码表示如果前面的路径,如/system/maintenance.html等,都找不到,就会反向代理到http://backend服务上。还可以用指定错误码的方式与error_page配合使用,例如:
location / { try_files $uri $uri/ /error.phpc=404 =404; }
2.4.3 内存及磁盘资源的分配
下面介绍处理请求时内存、磁盘资源分配的配置项。
(1)HTTP包体只存储到磁盘文件中
语法:client_body_in_file_only on|clean|off;
默认:client_body_in_file_only off;
配置块:http、server、location
当值为非off时,用户请求中的HTTP包体一律存储到磁盘文件中,即使只有0字节也会存储为文件。当请求结束时,如果配置为on,则这个文件不会被删除(该配置一般用于调试、定位问题),但如果配置为clean,则会删除该文件。
(2)HTTP包体尽量写入到一个内存buffer中
语法:client_body_in_single_buffer on|off;
默认:client_body_in_single_buffer off;
配置块:http、server、location
用户请求中的HTTP包体一律存储到内存buffer中。当然,如果HTTP包体的大小超过了下面client_body_buffer_size设置的值,包体还是会写入到磁盘文件中。
(3)存储HTTP头部的内存buffer大小
语法:client_header_buffer_size size;
默认:client_header_buffer_size 1k;
配置块:http、server
上面配置项定义了正常情况下Nginx接收用户请求中HTTP header部分(包括HTTP行和HTTP头部)时分配的内存buffer大小。有时,请求中的HTTP header部分可能会超过这个大小,这时large_client_header_buffers定义的buffer将会生效。
(4)存储超大HTTP头部的内存buffer大小
语法:large_client_header_buffers number size;
默认:large_client_header_buffers 48k;
配置块:http、server
large_client_header_buffers定义了Nginx接收一个超大HTTP头部请求的buffer个数和每个buffer的大小。如果HTTP请求行(如GET/index HTTP/1.1)的大小超过上面的单个buffer,则返回"Request URI too large"(414)。请求中一般会有许多header,每一个header的大小也不能超过单个buffer的大小,否则会返回"Bad request"(400)。当然,请求行和请求头部的总和也不可以超过buffer个数*buffer大小。
(5)存储HTTP包体的内存buffer大小
语法:client_body_buffer_size size;
默认:client_body_buffer_size 8k/16k;
配置块:http、server、location
上面配置项定义了Nginx接收HTTP包体的内存缓冲区大小。也就是说,HTTP包体会先接收到指定的这块缓存中,之后才决定是否写入磁盘。
注意:如果用户请求中含有HTTP头部Content-Length,并且其标识的长度小于定义的buffer大小,那么Nginx会自动降低本次请求所使用的内存buffer,以降低内存消耗。
(6)HTTP包体的临时存放目录
语法:client_body_temp_path dir-path[level1[level2[level3]]]
默认:client_body_temp_path client_body_temp;
配置块:http、server、location
上面配置项定义HTTP包体存放的临时目录。在接收HTTP包体时,如果包体的大小大于client_body_buffer_size,则会以一个递增的整数命名并存放到client_body_temp_path指定的目录中。后面跟着的level1、level2、level3,是为了防止一个目录下的文件数量太多,从而导致性能下降,因此使用了level参数,这样可以按照临时文件名最多再加三层目录。例如:
client_body_temp_path /opt/nginx/client_temp 1 2;
如果新上传的HTTP包体使用00000123456作为临时文件名,就会被存放在这个目录中。
/opt/nginx/client_temp/6/45/00000123456
(7)connection_pool_size
语法:connection_pool_size size;
默认:connection_pool_size 256;
配置块:http、server
Nginx对于每个建立成功的TCP连接会预先分配一个内存池,上面的size配置项将指定这个内存池的初始大小(即ngx_connection_t结构体中的pool内存池初始大小,9.8.1节将介绍这个内存池是何时分配的),用于减少内核对于小块内存的分配次数。需慎重设置,因为更大的size会使服务器消耗的内存增多,而更小的size则会引发更多的内存分配次数。
(8)request_pool_size
语法:request_pool_size size;
默认:request_pool_size 4k;
配置块:http、server
Nginx开始处理HTTP请求时,将会为每个请求都分配一个内存池,size配置项将指定这个内存池的初始大小(即ngx_http_request_t结构体中的pool内存池初始大小,11.3节将介绍这个内存池是何时分配的),用于减少内核对于小块内存的分配次数。TCP连接关闭时会销毁connection_pool_size指定的连接内存池,HTTP请求结束时会销毁request_pool_size指定的HTTP请求内存池,但它们的创建、销毁时间并不一致,因为一个TCP连接可能被复用于多个HTTP请求。8.7节会详述内存池原理。
2.4.4 网络连接的设置
下面介绍网络连接的设置配置项。
(1)读取HTTP头部的超时时间
语法:client_header_timeout time(默认单位:秒);
默认:client_header_timeout 60;
配置块:http、server、location
客户端与服务器建立连接后将开始接收HTTP头部,在这个过程中,如果在一个时间间隔(超时时间)内没有读取到客户端发来的字节,则认为超时,并向客户端返回408("Request timed out")响应。
(2)读取HTTP包体的超时时间
语法:client_body_timeout time(默认单位:秒);
默认:client_body_timeout 60;
配置块:http、server、location
此配置项与client_header_timeout相似,只是这个超时时间只在读取HTTP包体时才有效。
(3)发送响应的超时时间
语法:send_timeout time;
默认:send_timeout 60;
配置块:http、server、location
这个超时时间是发送响应的超时时间,即Nginx服务器向客户端发送了数据包,但客户端一直没有去接收这个数据包。如果某个连接超过send_timeout定义的超时时间,那么Nginx将会关闭这个连接。
(4)reset_timeout_connection
语法:reset_timeout_connection on|off;
默认:reset_timeout_connection off;
配置块:http、server、location
连接超时后将通过向客户端发送RST包来直接重置连接。这个选项打开后,Nginx会在某个连接超时后,不是使用正常情形下的四次握手关闭TCP连接,而是直接向用户发送RST重置包,不再等待用户的应答,直接释放Nginx服务器上关于这个套接字使用的所有缓存(如TCP滑动窗口)。相比正常的关闭方式,它使得服务器避免产生许多处于FIN_WAIT_1、FIN_WAIT_2、TIME_WAIT状态的TCP连接。
注意,使用RST重置包关闭连接会带来一些问题,默认情况下不会开启。
(5)lingering_close
语法:lingering_close off|on|always;
默认:lingering_close on;
配置块:http、server、location
该配置控制Nginx关闭用户连接的方式。always表示关闭用户连接前必须无条件地处理连接上所有用户发送的数据。off表示关闭连接时完全不管连接上是否已经有准备就绪的来自用户的数据。on是中间值,一般情况下在关闭连接前都会处理连接上的用户发送的数据,除了有些情况下在业务上认定这之后的数据是不必要的。
(6)lingering_time
语法:lingering_time time;
默认:lingering_time 30s;
配置块:http、server、location
lingering_close启用后,这个配置项对于上传大文件很有用。上文讲过,当用户请求的Content-Length大于max_client_body_size配置时,Nginx服务会立刻向用户发送413(Request entity too large)响应。但是,很多客户端可能不管413返回值,仍然持续不断地上传HTTP body,这时,经过了lingering_time设置的时间后,Nginx将不管用户是否仍在上传,都会把连接关闭掉。
(7)lingering_timeout
语法:lingering_timeout time;
默认:lingering_timeout 5s;
配置块:http、server、location
lingering_close生效后,在关闭连接前,会检测是否有用户发送的数据到达服务器,如果超过lingering_timeout时间后还没有数据可读,就直接关闭连接;否则,必须在读取完连接缓冲区上的数据并丢弃掉后才会关闭连接。
(8)对某些浏览器禁用keepalive功能
语法:keepalive_disable[msie6|safari|none]...
默认:keepalive_disablemsie6 safari
配置块:http、server、location
HTTP请求中的keepalive功能是为了让多个请求复用一个HTTP长连接,这个功能对服务器的性能提高是很有帮助的。但有些浏览器,如IE 6和Safari,它们对于使用keepalive功能的POST请求处理有功能性问题。因此,针对IE 6及其早期版本、Safari浏览器默认是禁用keepalive功能的。
(9)keepalive超时时间
语法:keepalive_timeout time(默认单位:秒);
默认:keepalive_timeout 75;
配置块:http、server、location
一个keepalive连接在闲置超过一定时间后(默认的是75秒),服务器和浏览器都会去关闭这个连接。当然,keepalive_timeout配置项是用来约束Nginx服务器的,Nginx也会按照规范把这个时间传给浏览器,但每个浏览器对待keepalive的策略有可能是不同的。
(10)一个keepalive长连接上允许承载的请求最大数
语法:keepalive_requests n;
默认:keepalive_requests 100;
配置块:http、server、location
一个keepalive连接上默认最多只能发送100个请求。
(11)tcp_nodelay
语法:tcp_nodelay on|off;
默认:tcp_nodelay on;
配置块:http、server、location
确定对keepalive连接是否使用TCP_NODELAY选项。
(12)tcp_nopush
语法:tcp_nopush on|off;
默认:tcp_nopush off;
配置块:http、server、location
在打开sendfile选项时,确定是否开启FreeBSD系统上的TCP_NOPUSH或Linux系统上的TCP_CORK功能。打开tcp_nopush后,将会在发送响应时把整个响应包头放到一个TCP包中发送。
2.4.5 MIME类型的设置
下面是MIME类型的设置配置项。
❑ MIME type与文件扩展的映射
语法:type{...};
配置块:http、server、location
定义MIME type到文件扩展名的映射。多个扩展名可以映射到同一个MIME type。例如:
types { text/html html; text/html conf; image/gif gif; image/jpeg jpg; }
❑ 默认MIME type
语法:default_type MIME-type;
默认:default_type text/plain;
配置块:http、server、location
当找不到相应的MIME type与文件扩展名之间的映射时,使用默认的MIME type作为HTTP header中的Content-Type。
❑ types_hash_bucket_size
语法:types_hash_bucket_size size;
默认:types_hash_bucket_size 32|64|128;
配置块:http、server、location
为了快速寻找到相应MIME type,Nginx使用散列表来存储MIME type与文件扩展名。types_hash_bucket_size设置了每个散列桶占用的内存大小。
❑ types_hash_max_size
语法:types_hash_max_size size;
默认:types_hash_max_size 1024;
配置块:http、server、location
types_hash_max_size影响散列表的冲突率。types_hash_max_size越大,就会消耗更多的内存,但散列key的冲突率会降低,检索速度就更快。types_hash_max_size越小,消耗的内存就越小,但散列key的冲突率可能上升。
2.4.6 对客户端请求的限制
下面介绍对客户端请求的限制的配置项。
(1)按HTTP方法名限制用户请求
语法:limit_except method...{...}
配置块:location
Nginx通过limit_except后面指定的方法名来限制用户请求。方法名可取值包括:GET、HEAD、POST、PUT、DELETE、MKCOL、COPY、MOVE、OPTIONS、PROPFIND、PROPPATCH、LOCK、UNLOCK或者PATCH。例如:
limit_except GET { allow 192.168.1.0/32; deny all; }
注意,允许GET方法就意味着也允许HEAD方法。因此,上面这段代码表示的是禁止GET方法和HEAD方法,但其他HTTP方法是允许的。
(2)HTTP请求包体的最大值
语法:client_max_body_size size;
默认:client_max_body_size 1m;
配置块:http、server、location
浏览器在发送含有较大HTTP包体的请求时,其头部会有一个Content-Length字段,client_max_body_size是用来限制Content-Length所示值的大小的。因此,这个限制包体的配置非常有用处,因为不用等Nginx接收完所有的HTTP包体——这有可能消耗很长时间——就可以告诉用户请求过大不被接受。例如,用户试图上传一个10GB的文件,Nginx在收完包头后,发现Content-Length超过client_max_body_size定义的值,就直接发送413("Request Entity Too Large")响应给客户端。
(3)对请求的限速
语法:limit_rate speed;
默认:limit_rate 0;
配置块:http、server、location、if
此配置是对客户端请求限制每秒传输的字节数。speed可以使用2.2.4节中提到的多种单位,默认参数为0,表示不限速。
针对不同的客户端,可以用$limit_rate参数执行不同的限速策略。例如:
server { if ($slow) { set $limit_rate 4k; } }
(4)limit_rate_after
语法:limit_rate_after time;
默认:limit_rate_after 1m;
配置块:http、server、location、if
此配置表示Nginx向客户端发送的响应长度超过limit_rate_after后才开始限速。例如:
limit_rate_after 1m; limit_rate 100k;
11.9.2节将从源码上介绍limit_rate_after与limit_rate的区别,以及HTTP框架是如何使用它们来限制发送响应速度的。
2.4.7 文件操作的优化
下面介绍文件操作的优化配置项。
(1)sendfile系统调用
语法:sendfile on|off;
默认:sendfile off;
配置块:http、server、location
可以启用Linux上的sendfile系统调用来发送文件,它减少了内核态与用户态之间的两次内存复制,这样就会从磁盘中读取文件后直接在内核态发送到网卡设备,提高了发送文件的效率。
(2)AIO系统调用
语法:aio on|off;
默认:aio off;
配置块:http、server、location
此配置项表示是否在FreeBSD或Linux系统上启用内核级别的异步文件I/O功能。注意,它与sendfile功能是互斥的。
(3)directio
语法:directio size|off;
默认:directio off;
配置块:http、server、location
此配置项在FreeBSD和Linux系统上使用O_DIRECT选项去读取文件,缓冲区大小为size,通常对大文件的读取速度有优化作用。注意,它与sendfile功能是互斥的。
(4)directio_alignment
语法:directio_alignment size;
默认:directio_alignment 512;
配置块:http、server、location
它与directio配合使用,指定以directio方式读取文件时的对齐方式。一般情况下,512B已经足够了,但针对一些高性能文件系统,如Linux下的XFS文件系统,可能需要设置到4KB作为对齐方式。
(5)打开文件缓存
语法:open_file_cache max=N[inactive=time]|off;
默认:open_file_cache off;
配置块:http、server、location
文件缓存会在内存中存储以下3种信息:
❑ 文件句柄、文件大小和上次修改时间。
❑ 已经打开过的目录结构。
❑ 没有找到的或者没有权限操作的文件信息。
这样,通过读取缓存就减少了对磁盘的操作。
该配置项后面跟3种参数。
❑ max:表示在内存中存储元素的最大个数。当达到最大限制数量后,将采用LRU(Least Recently Used)算法从缓存中淘汰最近最少使用的元素。
❑ inactive:表示在inactive指定的时间段内没有被访问过的元素将会被淘汰。默认时间为60秒。
❑ off:关闭缓存功能。
例如:
open_file_cache max=1000 inactive=20s;
(6)是否缓存打开文件错误的信息
语法:open_file_cache_errors on|off;
默认:open_file_cache_errors off;
配置块:http、server、location
此配置项表示是否在文件缓存中缓存打开文件时出现的找不到路径、没有权限等错误信息。
(7)不被淘汰的最小访问次数
语法:open_file_cache_min_uses number;
默认:open_file_cache_min_uses 1;
配置块:http、server、location
它与open_file_cache中的inactive参数配合使用。如果在inactive指定的时间段内,访问次数超过了open_file_cache_min_uses指定的最小次数,那么将不会被淘汰出缓存。
(8)检验缓存中元素有效性的频率
语法:open_file_cache_valid time;
默认:open_file_cache_valid 60s;
配置块:http、server、location
默认为每60秒检查一次缓存中的元素是否仍有效。
2.4.8 对客户端请求的特殊处理
下面介绍对客户端请求的特殊处理的配置项。
(1)忽略不合法的HTTP头部
语法:ignore_invalid_headers on|off;
默认:ignore_invalid_headers on;
配置块:http、server
如果将其设置为off,那么当出现不合法的HTTP头部时,Nginx会拒绝服务,并直接向用户发送400(Bad Request)错误。如果将其设置为on,则会忽略此HTTP头部。
(2)HTTP头部是否允许下划线
语法:underscores_in_headers on|off;
默认:underscores_in_headers off;
配置块:http、server
默认为off,表示HTTP头部的名称中不允许带“_”(下划线)。
(3)对If-Modified-Since头部的处理策略
语法:if_modified_since[off|exact|before];
默认:if_modified_since exact;
配置块:http、server、location
出于性能考虑,Web浏览器一般会在客户端本地缓存一些文件,并存储当时获取的时间。这样,下次向Web服务器获取缓存过的资源时,就可以用If-Modified-Since头部把上次获取的时间捎带上,而if_modified_since将根据后面的参数决定如何处理If-Modified-Since头部。
相关参数说明如下。
❑ off:表示忽略用户请求中的If-Modified-Since头部。这时,如果获取一个文件,那么会正常地返回文件内容。HTTP响应码通常是200。
❑ exact:将If-Modified-Since头部包含的时间与将要返回的文件上次修改的时间做精确比较,如果没有匹配上,则返回200和文件的实际内容,如果匹配上,则表示浏览器缓存的文件内容已经是最新的了,没有必要再返回文件从而浪费时间与带宽了,这时会返回304 Not Modified,浏览器收到后会直接读取自己的本地缓存。
❑ before:是比exact更宽松的比较。只要文件的上次修改时间等于或者早于用户请求中的If-Modified-Since头部的时间,就会向客户端返回304 Not Modified。
(4)文件未找到时是否记录到error日志
语法:log_not_found on|off;
默认:log_not_found on;
配置块:http、server、location
此配置项表示当处理用户请求且需要访问文件时,如果没有找到文件,是否将错误日志记录到error.log文件中。这仅用于定位问题。
(5)merge_slashes
语法:merge_slashes on|off;
默认:merge_slashes on;
配置块:http、server、location
此配置项表示是否合并相邻的“/”,例如,//test///a.txt,在配置为on时,会将其匹配为location/test/a.txt;如果配置为off,则不会匹配,URI将仍然是//test///a.txt。
(6)DNS解析地址
语法:resolver address...;
配置块:http、server、location
设置DNS名字解析服务器的地址,例如:
resolver 127.0.0.1 192.0.2.1;
(7)DNS解析的超时时间
语法:resolver_timeout time;
默认:resolver_timeout 30s;
配置块:http、server、location
此配置项表示DNS解析的超时时间。
(8)返回错误页面时是否在Server中注明Nginx版本
语法:server_tokens on|off;
默认:server_tokens on;
配置块:http、server、location
表示处理请求出错时是否在响应的Server头部中标明Nginx版本,这是为了方便定位问题。
2.4.9 ngx_http_core_module模块提供的变量
在记录access_log访问日志文件时,可以使用ngx_http_core_module模块处理请求时所产生的丰富的变量,当然,这些变量还可以用于其他HTTP模块。例如,当URI中的某个参数满足设定的条件时,有些HTTP模块的配置项可以使用类似$arg_PARAMETER这样的变量。又如,若想把每个请求中的限速信息记录到access日志文件中,则可以使用$limit_rate变量。
表2-1列出了ngx_http_core_module模块提供的这些变量。
表2-1 ngx_http_core_module模块提供的变量