Nginx的配置块嵌套
main
http{
upstream {...}
split_clients {...}
map {...}
geo {...}
server {
if () {...}
location {
limit_except {...}
}
location {
location {...}
}
}
server {...}
}
http 配置块之外的部分我们称之为main,像事件模块,配置进程个数之类的都是写在main中的。
http中最核心的是server块、location块。一个http块中可以有多个server块和location块。nginx会根据链接中的域名找到对应的server块,然后根据uri路径找到对应的location块。
nginx中的配置指令有其对应的上下文范围。就是说有些配置只能放在某个配置块中,而不能出现在其他配置块中。
例如log_format指令在配置文件中用于指定每一行配置文件的格式。
文档对其介绍为:
Syntax: log_format name [escape=default|json|none] string ...;
Default:
log_format combined "...";
Context: http
其中Context就是该指令的上下文,表示log_format只能出现在http块中。
access_log指令
Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default:
access_log logs/access.log combined;
Context: http, server, location, if in location, limit_except
access_log配置可以出现在http, server, location, if in location, limit_except配置块中。
如果一个指令出现在多个配置块中,他们的优先级如何,是否可以合并?
指令分为两种
值指令: 存配置项的值的指令,这类指令可以合并,如 root,access_log,gzip
动作类指令:指定行为,这类不可以合并,如rewrite,proxy_pass
对于值指令,如果同时出现在多个配置块中,则遵循以下原则:
子配置不存在,直接使用父配置块的指令。
子配置存在,则覆盖父配置块的指令。
即子配置中的指令优先级更高。
例如:
http {
server {
listen 8080;
root /home/geek/nginx/html;
access_log logs/geek.access.log.log main;
location /test {
root /home/geek/nginx/test;
access_log logs/access.test.log main;
}
location /dlib {
alias dlib/;
}
location / {
}
}
}
如server下定义的root /home/geek/nginx/html; 表示凡是访问本服务器8080端口的请求都指向/home/geek/nginx/html目录。
第三个location中没有定义root或者alias,此时就会使用server的root指令配置的内容。
第一个location有定义root,那么会用它自己的root配置
每一个模块下面有些什么指令,指令的格式和参数,上下文等都在nginx官网文档中有详细说明。
listen 指令
context是server,只能在server中使用。
示例:
listen unix:/var/run/nginx.sock;
listen 127.0.0.1:8000; # 只有内网可以访问,外网无法访问
listen 127.0.0.1; # 默认80端口
listen 8000; # 任何ip都可以访问
listen *:8000; # 同 listen 8000;
listen [::1];
listen [::]:8000 ipv6only=on;
等等。
Nginx 接收请求的过程
Nginx接收请求过程
从上图可以看到三次握手之后,连接建立,操作系统内核会选中CPU中的某一个worker进程,将连接句柄传给epoll_wait这个函数,调用accept方法并分配连接内存池 connection_pool_size,默认是512个字节。
从epoll_wait到accept都是nginx的事件模块的工作。
接下来accept会把请求交给http模块去处理,然后事件模块就去处理其他的读事件或者写事件了。
而http模块开启,调用ngx_http_init_connection设置回调方法epoll_ctl,添加超时定时器,设置client_header_timeout默认60s。
此时只是建立了连接,把http模块给唤醒了而已。还没有真正开始处理请求。
当客户端真正开始发送http请求,服务端的操作系统接受一个客户端发来的DATA数据包(应用层),然后TCP层返回一个ACK数据包给客户端表示服务端收到了请求。
然后系统内核将这个DATA发送给nginx事件模块的epoll_wait函数,再交给HTTP模块处理,ngx_http_wait_request_handler分配内存来读http请求(参数client_header_buffer_size),默认是1k。这1k的内存是用来解析请求行的。
所以无论是建立连接和接收请求,nginx都要分配内存给每一个连接和每一个请求,建立的连接越多,处理的请求越多就越耗内存。
然后HTTP模块就开始接受URI,解析请求行(就是HTTP报文第一行中\r\n之前的部分,包括方法名POST/GET、URI、协议)。
Nginx解析HTTP请求头的流程
GET /full/000178f3e94cb440ff977d6a227d9ab1fdaca180.jpg HTTP/1.1\r\n
这就是一个请求行
如果发现URI很长,超过了刚刚分配的1k内存,nginx会分配更大的内存来解析请求行。
当解析完请求行,标识完URI,就开始接受和解析请求头header,请求头的大小就比请求行内容大多了。
此时nginx会分配更大的内存来解析header,然后标识header。
解析完请求行和请求头,nginx会移除超时定时器,然后开始11个阶段的HTTP请求处理。