简介
Nginx是一款轻量级Web服务器/反向代理服务器及电子邮件代理服务器,并在BSD-like协议下发行。由俄罗斯程序设计师lgorSysoev所开发,供俄国大型的入口网站及搜索引擎使用,其特点是占有内存少,并发能力强,在同类型的网页服务器中表现较好,中国大陆使用Nginx网站用户有:新浪、网易、腾讯、小米官网等。
架构
我们可以看到,Nginx是以多进程的方式工作,当然Nginx也是支持多线程的方式,只是我们主流的方式还是多进程的方式。也是Nginx的默认方式。Nginx采用多进程有诸多好处
Nginx的优势
首先,对于每个worker进程,独立的进程不需要加锁,所以节省了锁的开销,同时在编程问题排查上方便很多。其次采用独立的进程,可以让相互之间不会影响,一个进程退出后,其他进程还在工作,服务不会中断,master进程则很快重启新的worker进程
为什么有优势
抛出问题,Nginx采用多worker的方式处理请求,每个worker里只有一个主线程,能够处理并发数很有限,多少进程处理多少并发,何来高并发?
这就是Nginx的高明之处,Nginx采用异步非阻塞的方式处理请求,也就是说Nginx可以处理成千上万个请求。
我们来看一个请求的完整过程。首先,请求过来,先建立连接,然后在接收数据,接收后在发送数据。具体到系统底层,就是读写事件,当读写事件没有准备好,那就只能等,等事件准备好了再继续。阻塞调用会进入内核等待,CPU会让出去给别人用,对单线程的worker显然不合适,当网络事件越来越多时,都在等待,CPU利用率低下,更别说高并发了。所以Nginx里最忌讳阻塞的系统调用。非阻塞就是说事件没有准备好马上返回EAGAIN,事件还没准备好,等会再来看吧。然后你过了一会来检查一下事件,知道事件准备好了为止,在这期间,你可以做其他事情,再来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也不小,所以才有了异步非阻塞的事件处理机制,具体到系统调用就是像select/poll/epoll这样的系统调用。提供一种机制,让你同时监控多个事件,调用它们是阻塞的,但可以设置超时时间,在超时时间内,有时间准备好了就返回。解决了我们上面的两个问题,那epoll为例,当事件没准备好,才在epoll里面。这样,我们就是处理大量的并发,当然,这里的并发请求,是指未处理的请求,线程只有一个,所以同时能处理请求当然只有一个了,只是在请求间进行不断地切换而已,切换也是因为异步事件为准备好的事件。与多线程相比,这种事件处理方式是有很大优势大的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。更多的并发数,只是会占用更多的内存。现在的网络服务器都采用这种方式。
上面的讲解知道了网络事件的处理,那么如何处理信号与定时器?
对于Nginx正在等待时间(epoll_wait),如果程序收到信号,在信号处理函数处理完后,epoll_wait()返回错误,然后程序可再次进入epoll_wait.
另外,定时器,由于epoll_wait等函数在调用的时候可以设置一个超时时间,Nginx借助超时时间实现定时器,Nginx里面定时器事件放在一个最小堆,每次进入epoll_wait前,先从堆里拿到所有定时器的最小时间,计算出epoll_wait的超时时间进入epoll_wait。所有没事件产生,也没有中断信号时,epoll_wait会超时。所以我们写Nginx代码时,处理网络事件的回调函数时,通常先判断超时。
我们用一段伪代码来总结一下Nginx的事件处理模型
好,今天我们就看到这里