这篇博客简单看一看Nginx的工作流程和机制,当然不涉及源码,我还没到那种水平。


Nginx工作流程

先来看一张官网图:

nginx普通用户启动 nginx启动流程_恰饭

框框里面的是Nginx的架构,可以看到它里面分为了masterworker。请求进来后由master分发任务,worker负责执行或反向代理给别的服务单元。

我们启动Nginx后,执行以下命令,查看后台有关Nginx的进程:

ps -ef | grep nginx

nginx普通用户启动 nginx启动流程_nginx_02


可以看到有一个master进程与worker进程,验证了图片的架构。

接下来再放一张,具体来看一下怎么个工作流程法:

nginx普通用户启动 nginx启动流程_nginx普通用户启动_03

这张图就比较形象,图中client作为浏览器。

当浏览器请求进来后,它先通知master进程,master进程收到请求后,会去通知名下空闲的worker进程,告诉它们有新的请求啦。再之后这些worker会去争抢,谁抢到这个请求就算谁的。抢到之后,由于Nginx不能直接处理java的要求,需要Tomcat来做处理,所以这个时候抢到请求的worker会反向代理给后面的Tomcat执行。

大致的流程就是这样。就好像一个地主家(master)要收购米(浏览器发送的请求),但是这位地主热心肠,他会把收来的米送给下面的工人(worker)。可惜米数量有限呀,于是地主想了个办法,米收购完之后,地主放着,让底下的工人们过来抢,谁抢到就算谁的。这就是我们说的masterworker机制。


该机制的好处

  1. 还记得Nginx有一个命令吗:
./nginx -s reload

这个命令可以重新加载Nginx,使配置热部署生效。

那和我们的master-worker机制有什么关系呢?

别急,现在来了。在master-worker机制下,当一个worker抢到请求时,那么它会去反向代理给后面的Tomcat,让其去处理并返回。在这个过程中,我们能够使用上述的热部署命令加载Nginx,是因为其它没抢到的worker去热加载自身,使其满足最新的配置,而抢到的worker正在工作中(因为抢到请求,需要先处理),等待其工作完成之后也会去热加载自身。这么做有个好处,可以在不影响处理请求的情况下去更新Nginx的配置。也就是“无缝热部署”。

  1. 第二个好处其实和第一个有点像,就是每个worker都是一个进程,所以就不需要加锁,大大节省了锁的开销。同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的worker 进程。当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。

设置多少个worker合适?

Nginx 同 redis 类似都采用了 io 多路复用机制,每个 worker 都是一个独立的进程,但每个进程里只有一个主线程,通过异步非阻塞的方式来处理请求, 即使是千上万个请求也不在话下。

每个 worker 的线程可以把一个 cpu 的性能发挥到极致。所以 worker 数和服务器的 cpu数相等是最为适宜的。设少了会浪费 cpu,设多了会造成 cpu 频繁切换上下文带来的损耗。

也就是说,你cpu是几核的,那么worker就多少个。

worker的数量配置,可以直接在Nginx的配置文件下的全剧快中进行修改:

nginx普通用户启动 nginx启动流程_Nginx_04

关于这一块,可以参考以前的博客


一点小练习

在此之前,引入一个概念:

连接数 worker_connection表示每个 worker 进程所能建立连接的最大值。

那么问题开始。

  • 发送请求,占用了 woker 的几个连接数?
    答案是2个或者4个。来两张图片解释下。
    当浏览器请求是静态请求时,worker直接返回资源,所以是2个:

nginx普通用户启动 nginx启动流程_Nginx_05

我们已经知道Nginx实际的工作模块是worker,所以图片直接用worker表示。

当浏览器请求是动态请求时,worker去反向代理找Tomcat处理,所以是4个:

nginx普通用户启动 nginx启动流程_nginx_06


关于动静分离的知识,可以参考之前的博客

  • 第二个问题,nginx 有一个 master,有四个 woker,每个 woker 支持最大的连接数 1024,支持的最大并发数是多少?
    这一问题也是分动态和静态请求。当前请求如果是静态请求时,则:
    最大并发数=worker个数(4)*worker支持的最大连接数(1024)/ 所消耗的连接数(2)=2048
    如果是动态请求时,同理,则有:
    最大并发数=worker个数(4)*worker支持的最大连接数(1024)/ 所消耗的连接数(4)=1024

关于上述公式简单说明一下,最大并发数无非就是当前所有的worker加起来最多可以同时处理多少个请求。那就是所有worker的连接数(worker个数*worker支持的最大连接数),但其中因为动静请求的问题会有来回,损耗了连接数(根据第一个问题可知)。所以所有worker的连接数还需根据请求的类别除以2或4.