跳到主要内容

五、Nginx 基础概念

Nginx 基础概念

connection

在Nginx 中 connection 就是对 tcp 连接的封装,其中包括连接的 socket,读事件,写事件。利用 Nginx 封装的 connection,我们可以很方便的使用 Nginx 来处理与连接相关的事情,比如,建立连接,发送与接受数据等。而 Nginx 中的 http 请求的处理就是建立在 connection之上的,所以 Nginx 不仅可以作为一个web服务器,也可以作为邮件服务器。当然,利用 Nginx 提供的 connection,我们可以与任何后端服务打交道。

结合一个 tcp 连接的生命周期,我们看看 Nginx 是如何处理一个连接的。首先,Nginx 在启动时,会解析配置文件,得到需要监听的端口与 ip 地址,然后在 Nginx 的 master 进程里面,先初始化好这个监控的 socket(创建 socket,设置 addrreuse 等选项,绑定到指定的 ip 地址端口,再 listen),然后再 fork 出多个子进程出来,然后子进程会竞争 accept 新的连接。此时,客户端就可以向 Nginx 发起连接了。当客户端与服务端通过三次握手建立好一个连接后,Nginx 的某一个子进程会 accept 成功,得到这个建立好的连接的 socket,然后创建 Nginx 对连接的封装,即 ngx_connection_t 结构体。接着,设置读写事件处理函数并添加读写事件来与客户端进行数据的交换。最后,Nginx 或客户端来主动关掉连接,到此,一个连接就寿终正寝了。

当然,Nginx 也是可以作为客户端来请求其它 server 的数据的(如 upstream 模块),此时,与其它 server 创建的连接,也封装在 ngx_connection_t 中。作为客户端,Nginx 先获取一个 ngx_connection_t 结构体,然后创建 socket,并设置 socket 的属性( 比如非阻塞)。然后再通过添加读写事件,调用 connect/read/write 来调用连接,最后关掉连接,并释放 ngx_connection_t。

在Nginx 中,每个进程会有一个连接数的最大上限,这个上限与系统对 fd 的限制不一样。在操作系统中,通过 ulimit -n,我们可以得到一个进程所能够打开的 fd 的最大数,即 nofile,因为每个 socket 连接会占用掉一个 fd,所以这也会限制我们进程的最大连接数,当然也会直接影响到我们程序所能支持的最大并发数,当 fd 用完后,再创建 socket 时,就会失败。Nginx 通过设置 worker_connectons 来设置每个进程支持的最大连接数。如果该值大于 nofile,那么实际的最大连接数是 nofile,Nginx 会有警告。Nginx 在实现时,是通过一个连接池来管理的,每个 worker 进程都有一个独立的连接池,连接池的大小是 worker_connections。这里的连接池里面保存的其实不是真实的连接,它只是一个 worker_connections 大小的一个 ngx_connection_t 结构的数组。并且,Nginx 会通过一个链表 free_connections 来保存所有的空闲 ngx_connection_t,每次获取一个连接时,就从空闲连接链表中获取一个,用完后,再放回空闲连接链表里面。