nginx运行原理

nginx启动后会有一个master进程和多个worker进程。
nginx运行原理_第1张图片

master进程用来管理worker进程,包括:接受来自外界的信号,向个worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动启动新的worker进程。
master进程充当整个进程组与用户的交互接口,同时对进程进行监护,他不需要处理网络时间,不负责业务的执行,只会通过管理worker进程来实现重启服务,平滑升级,管理日志文件,配置文件实时生效等功能。
我们控制nginx,只需要通过kill向master进程发送信号就行了。比如 kill -HUP pid,从容重启nginx,服务是不中断的。因为matser进程接受信号后,会重新加载配置文件,然后再启动新的worker进程,并向老的worker进程发送信号,告送他可以退休。新的worker在起动后就开始接受新的请求,而老的worker在收到master的信号后,就不再接受新的请求,并且在当前进程中处理完所有请求后再退出。

worker进程处理基本的网络事件。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各个进程相互之间是独立的。一个请求只可能在一个worker进程中处理,一个worker进程,不可能处理其他进程的请求。
首先每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

优点:
1、对于每个worker进程来说,都是独立的进程,不需要加锁,所以省掉了锁带来的开销。
2、采用独立的进程,可以让互相之间不会影响,一个进程退出后,其他进程还在工作,服务不会中断,master进程则会很快的启动新的worker进程
3、如果worker进程异常退出,肯定是程序有bug,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,降低了风险。

nginx的事件处理过程

首先看一下web服务器B/S
web服务器以B/S方式提供服务。浏览器和服务器的交互方式如下
nginx运行原理_第2张图片

1、浏览器向服务器发送http请求(request)
2、服务器收到浏览器的请求数据,经过分析处理,向浏览器输出响应数据(response)
3、浏览器收到服务器的响应数据,经过分析处理,将最终结果显示在浏览器中。

基于这个B/S,到达系统底层就是数据的读写事件,nginx采用的是异步非阻塞,具体到系统调用就是像liunx系统中的select、poll/epoll/kqueue。nginx默认使用epoll:
当事件没有准备好时,放到epoll里面,事件准备好了,我们就去读写,当读写返回engain时,我们将它再次放入到epoll里面。这样,只要有事件准备好了,我们就去处理它,只有当所有事件都没有准备好时,才在epoll里面等着。这样,我们就可以并发处理大量的并发了,当然,这里的并发请求是指未处理完的请求,线程只有一个,所以同时能处理的请求当然只有一个了,只是在请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的,这里的切换是没有任何代价,你可以理解为循环处理多个准备好的事件。于多线程相比,这种事件处理方式有很大的优势,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。更多的并发数只是会占用更多的内存而已。
推荐设置worker的个数是cpu的核数,这里就容易理解了,更多的worker数,只会导致进程来竞争cpu资源,从而带来不必要的上下文切换。

你可能感兴趣的:(nginx)