Nginx(一)请求处理

164 阅读7分钟

Nginx是一个轻量级Http服务器。使用Master管理进程+Worker工作进程的Multi-Reactor多进程模型设计。整体架构图大致如下: image.png

  • Master+Worker

    Matster管理Worker,Worker处理请求。

  • 后台服务

    Nginx可以代理后台服务,真正的服务可以是Web服务,应用服务,数据库服务等。

  • 缓存

    这里的cachemanager其实分为:proxy cache、cacheloader和cache manager。

    • cache manager

      定期清理过期缓存,基本策略LRU。

    • cache loader

      将缓存的文件映射到内存中。刚启动的时候就要把缓存文件加载到内存中。

进程模型

Nginx分为单工作进程模型(1个Master1个Worker)和多进程模型(1个Master多个Worker)。 Nginx共4个进程:Master、Worker、CacheLoader、CacheManager。

Master进程

  • Master进程充当整个进程组与用户交互的接口

    不具体处理网络事件、不负责业务的执行,只是管理worker进程来实现服务重启、平滑升级、更换日志文件、配置文件实时生效。

    • 加载配置文件
    • 启动工作进程
    • 非停升级平滑升级
  • 对Worker进程进行监护

    向各个Worker进程发送信号或管道方式进行控制,监控worker进程的运行状态。 如果有Worker意外退出,会自动启动新的worker进程。

Worker进程

  • 基本网络事件由Worker进程处理
  • 不同Worker平等、相互独立,一个请求只能交给一个Worker处理
  • 一般Worker进程数设置为CPU核心数worker_processes CPU核心数
  • Worker之间通过共享内存,原子操作等实现负载均衡
  • 关闭时,没有连接的Worker会直接关闭,其他Worker如果还有连接会等连接释放后才关闭。这也是多进程的好处,进程之间是相互独立的。

每个Worker进程都可以处理数以千计的网络请求,Worker进程可以同时处理的请求数只受限于内存大小。

Worker处理Web请求,与浏览器保持连接,处理响应。具体操作有读取请求、解析请求、处理请求、产生数据后,再返回给客户端,最后断开连接。

连接池

每个Worker进程有独立的ngx_cycle_t数据结构

进程管理:信号

上文提到Worker进程之间的通信会通过信号,并且主要通过信号。

  • Master进程
    • 监控Worker进程有没有发送CHLD信号(子进程终止会向父进程发送CHLD信号)
    • 管理Worker进程,接收TERM、INT(立刻停止);QUIT(优雅停止);HUP(重载配置文件);USER1(重新打开日志文件 做日志文件切割);USER2(关于热部署 找到Master PID发送);WINCH(关于热部署 找到Master PID发送);信号
  • Worker进程
    • 接收TERM、INT(立刻停止);QUIT(优雅停止);USER1(重新打开日志文件 做日志文件切割);WINCH(关于热部署 找到Master PID发送);信号
  • nginx命令行
    • reload:HUP
    • reopen:USER1
    • stop:TERM
    • quit:QUIT

Worker实现连接——抢占机制

一个连接过来后有多个Worker,如何决定要连接哪个Worker呢,这就涉及到Worker的抢占机制了。 Master监听指定端口,并fork出了多个Worker进程。当一个请求从客户端过来的时候,Worker需要抢占互斥锁/accept_mutex,抢占成功的Worker进行处理。

Worker默认的并发能力可通过worker_connections 1024设置。默认IO模型为epoll。

events{
    use epoll;
    worker_connections 1024
}

connection

Nginx中的connection其实就是对tcp连接的封装,包括socket以及读写事件。

Nginx连接_作为服务端

  1. Nginx刚启动时,解析配置文件,得到需要监听的IP地址和端口
  2. 在Master进程初始化socket
  3. Master进程fork多个worker进程,同时Worker进程会竞争accept新连接

完成以上三步后,客户端就可以向Nginx发起连接了。当进行TCP三次提手之后,Nginx的某一个Worker进程会accept成功,然后就根据这个socket,创建Nginx对socket的封装,即ngx_connection_t结构体。

Nginx连接_作为客户端

创建连接会封装在ngx_connection_t结构体,然后创建socket并设置属性,添加读写事件。

最大连接数

Nginx中进程的最大连接数上限和系统的FD连接数上限不同。Nginx中进程的最大连接数上限是前面提到的worker_connections设置的数值,操作系统进程的最大连接数是ulimit -n显示的FD最大数。如果操作系统的最大连接数小于Nginx的最大连接数也没关系,因为通过连接池来管理。

每个Worker进程会有1个连接池、1个链表

  • 连接池

    连接池大小是长度为worker_connections,数据结构为ngx_connection_t的数组。

  • 链表

    链表free_connections保存空闲ngx_connection_t。每获取一个连接,就从空闲链表中获取一个,用完放回链表。

如果Nginx作为应用服务器最大连接数为工作进程数worker_processes \* worker_connections

如果作为反向代理服务器为工作进程数worker_processes \* worker_connections/2,因为每个并发都会建立与客户端以及后端服务的连接。

模块设计

核心模块

  • ngx_http_module 定义HTTP模块
  • ngx_events_module 定义事件模块
  • ngx_mail_module 定义Mail模块
  • ngx_openssl_module 加载模块支持HTTPS请求
  • ngx_errlog_module 错误日志处理
  • ngx_core_module nginx启动后负责加载的第一个模块 主要用来保存全局对象。

HTTP模块

  • 标准HTTP模块

    提供HTTP协议解析相关的功能,比如:端口配置、网页编码设置、HTTP响应头设置等等。

  • 可选HTTP模块

    扩展标准的 HTTP 功能,让Nginx能处理一些特殊的服务,比如: Flash多媒体传输、解析GeoIP 请求、网络传输压缩、安全协议SSL支持等。

Event模块

负责事件的注册、分发处理、销毁。支持各类操作系统的事件驱动模型,例如epoll、poll、select、kqueue、eventport等。

Mail模块

邮件服务模块

配置模块

其他模块基础。

接收连接请求流程

结合以上对connection的分析和和http模块的简要介绍。HTTP模块处理前,nginx需要先建立连接,接收客户端发来的http请求。根据Header信息决定需要哪些模块,让HTTP模块知道怎样处理请求。

image.png

    1. 建立连接

    当用户发来SYN时,由内核回应SYN+ACK。

    1. 选中Worker进程 当操作系统内核收到最后一次握手消息ACK后,会通过负载均衡算法,操作系统选中Worker进程。
    1. epoll_wait

    Worker中的方法epoll_wait会返回建立好连接的句柄。

    1. accept

    监听到ACK读事件,会调用accept分配连接内存池。连接内存池分配大小connection_pool_size: 512

    内存池是可以扩展的。

    1. ngx_http_init_connection

    分配好内存池之后,accept分配连接内存池后会调用HTTP模块中的回调方法ngx_http_init_connection,http模块就会从事件模块接手请求,新建立的读事件会通过epoll_ctl加入epoll中,并添加超时定时器。client_header_timeout:xxs代表xxs后没有收到请求就超时了,完成这步后,事件模块就切到其他FD去处理了。

    1. 当用户传来真正的GET/POST请求

    操作系统会回复ACK。事件模块epoll_wait拿到请求,调用上一步设置好的在HTTP模块中的回调方法ngx_http_wait_request_handler,这个方法要把内核的数据读到用户态中,因为要读所以首先要分配内存。这个内存要分配多大?要从分配连接内存池connection_pool_size:xxx中分client_header_buffer_size:1k

    这里的大小代表,一旦用户有消息过来就会分配该大小如1k。

接收连接请求收到nginx中就行了,但是处理请求还需要分析协议header。

接收请求方法流程

image.png

请求上下文一般会将请求内存池设置为4K。

HTTP请求11个阶段

image.png 图中11个阶段依次执行。

性能优势

Nginx轻量级,拥有性能优势的原因有

异步非阻塞

CPU绑定

Worker绑定固定内核上,避免频繁切换上下文,提高缓存命中率。

负载均衡

Nginx使用全局互斥锁accept_mutex实现了一套负载均衡算法,避免Worker之间负载的不均衡;另外也避免了所有Worker争抢接收Accept连接,全部被唤醒导致“惊群效应”。