# Nginx 进阶
# Nginx 请求处理流程
Nginx 的请求处理流程大体是这样的:接收到 WEB、EMAIL、TCP 流量后,因为 Nginx 采用的非阻塞的事件驱动处理引擎,所以会有传输层状态机处理 TCP 流量,HTTP 状态机处理 WEB 流量,MAIL 状态机处理 EMAIL 流量,然后进行静态资源访问,如果是反向代理还能加入磁盘缓存,当分配的内存不足以完全缓存文件内容时,例如 sendfile 等大文件时,会退化成阻塞的磁盘调用,所以还会使用线程池处理磁盘阻塞调用,对于每一个处理完成的请求,会记录 Access 访问日志和 Error 错误日志,Nginx 作为负载均衡使用时,可以把请求通过协议机传输到后面的服务器。
# Nginx 架构
Nginx 可以分为单进程和多进程模式,单进程一般作为调试开发使用,在生产环境一般用多进程。
Nginx 多进程模式,有一个主进程和其他子进程(包括 Worker 进程 和 cache 相关进程:Cache manager、Cache loader)。主进程的主要工作是加载和执行配置文件,并且驻留子进程。子进程用来作为实际的请求处理。Nginx 采取基于事件的模型和 OS 依赖的机制,在多个子进程之间高效的分配请求。子进程的个数会直接写在配置文件中,并且对于给定的配置可以是固定的,也可以根据可用的 CPU 核数自动进行调整。缓存相关的内容是各进程共享的,反向代理时,Cache manager 进程管理上游的缓存,Cache loader 进程载入上游的缓存。
# Nginx 进程管理:信号
Nginx 的多进程通信是使用的共享内存方式,Nginx 的进程管理使用的是信号。
# Master 进程
# 监控 Worker 进程
Master 进程会监控 Worker 进程有没有发来的 CHLD 信号,Linux 系统规定,当子进程终止时,会向父进程发送 CHLD 信号。当 Worker 进程因为某些原因报错终止时,会向 Master 进程发送 CHLD 信号,Master 进程接收到信号后,会拉起一个新的 Worker 进程。
# 管理 Worker 进程
Master 进程会接收到一些信号来管理 Worker 进程。
既可以使用 Nginx 命令行,也可以使用 kill 指令的方式接收的信号有以下几种:
- TERM,INT 立刻停止 Nginx 进程,对应
nginx -s stop
- QUIT 优雅停止,对应
nginx -s quit
- HUP 重新载入配置文件,对应
nginx -s reload
- USR1 重新打开日志文件,做日志切割,对应
nginx -s reopen
以上几种信号用 Nginx 命令行可以起到同样的作用是因为,Nginx 在启动时,一般会默认在 Nginx 安装目录的 logs 文件夹下 nginx.pid 中记录 Nginx 的 Master 进程 pid,在执行 nginx -s 命令时,这个命令行工具会向 nginx.pid 记录的 pid 发送相应的信号。
只能使用 kill 指令的方式接收的信号:
- USR2
- WINCH
# Worker 进程
Worker 进程也可以接收一些信号,只能使用 kill + 进程 id 的方式:
- TERM,INT
- QUIT
- USR1
- WINCH
通常我们不直接对 Worker 进程发送信号,因为规范的方式是通过 Master 进程来管理 Worker 进程
# Nginx reload 流程
- 向 Master 进程发送 HUP 信号(reload 命令)
- Master 进程校验配置语法是否正确
- Master 进程打开新的监听端口(如果有新端口的话,因为子进程的端口会继承父进程的端口)
- Master 进程用新配置启动新的 Worker 子进程
- Master 进程向老 Worker 子进程发送 QUIT 信号
- 老 Worker 子进程关闭监听句柄,处理完当前连接后结束进程(为了避免老 Worker 子进程长时间存在,可以设置 worker_shutdown_timeout 超时时间)
# Nginx 热升级流程
- 将旧 Nginx 文件换成新 Nginx 文件(注意备份)
- 向 master 进程发送 USR2 信号
- master 进程修改 pid 文件名,加后缀 .oldbin
- master 进程用新 Nginx 文件启动新 master 进程
- 向老 master 进程发送 QUIT 信号,关闭老 master 进程
- 回滚:向老 master 发送 HUP,向新 master 发送 QUIT
# worker 进程优雅关闭(quit)
- 设置定时器 worker_shutdown_timeout
- 关闭监听句柄
- 关闭空闲连接
- 在循环中等待全部连接关闭(时间可能会较长,当超过 worker_shutdown_timeout 设置的时间,worker 进程会把剩下的连接直接关闭)
- 退出进程
# 共享内存
跨 worker 进程通信的关键是共享内存,官方 Nginx 模块使用了共享内存的有以下几个:
- ngx_http_lua_api
- rbtree 数据结构
- ngx_stream_limit_conn_module
- ngx_http_limit_conn_module
- ngx_stream_limit_req_module
- http cache 相关
- ngx_http_file_cache
- ngx_http_proxy_module
- ngx_http_scgi_module
- ngx_http_uwsgi_module
- ngx_http_fastcgi_module
- ssl 相关
- ngx_http_ssl_module
- ngx_mail_ssl_module
- ngx_stream_ssl_module
- 单链表数据结构
- ngx_http_upstream_zone_module
- ngx_stream_upstream_zone_module