nginx学习笔记(1)---nginx的基本架构

tengine是淘宝网发起的一个开源项目,它在nginx的基础上添加了很多高级功能和特性,其性能和稳定性在淘宝网、天猫商城这样的大访问网站得到了很好的检验。tengine的官方网站(http://tengine.taobao.org)上有源代码的下载和很多学习文档。tengine官网上的文档讲的比较详细,内容较多。后续我将较为简洁地整理自己学习的笔记,也方便今后自己后顾。


nginx的基本架构

---

nginx默认是以多进程的方式来工作的:nginx在启动后,以daemon的方式在后台运行,会有一个master进程和多个worker进程。


master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。

基本的网络事件都是放在worker进程中来处理的。 多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致(更多的worker只会导致进程来竞争CPU资源,从而带来不必要的上下文切换。nginx为了更好的利用多核特性,提供了CPU亲缘性的绑定选项,可以将某个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效)。nginx的进程模型如下图(该图引自tengine文档):


由于master来管理worker进程,我们只需要与master通信就行了

以nginx -s reload重启为例:执行此命令之后,会新起一个nginx进程,新进程解析到reload参数后,就知道是要控制nginx来重新加载配置文件,它会向master进程发送信号。master接收到信道后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以退休了。新的worker在启动后就开始接收新的请求,而老的worker进程在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成之后,再退出。


worker进程又如何处理请求

worker进程之间是平等的,每个进程处理请求的机会也是一样的。 当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程。所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

nginx采用这种进程模型的好处

首先,对于每个worker进程来说,独立的进程不需要加锁,省掉了锁带来的开销,同时在编程以及问题查找时也会方便很多;

其次,采用独立的进程,可以让相互之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程可以很快启动新的worker进程。

(避免上下文切换带来的CPU开销)


nginx光靠这种多进程模式就能实现高并发吗?每个worker里面只有一个主线程,岂不是有多少个worker进程就只能有多少个并发?

nginx采用异步非阻塞的方式来处理请求,这样才能实现同时处理成千上万个请求。


什么叫异步非阻塞

当一个请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。具体到系统底层就是读写事件。当读写事件没有准备好时,那就会出现阻塞调用,只有等事件准备好了再继续。当大量的网络事件都在等待时,会导致CPU利用率上不去。如果想要通过加进程来提高并发数,这就类似于apache的线程模型了,会增加上下文切换带来的CPU开销。

非阻塞就是,事件没准备好时,就过会再来检查事件,这期间就可以先去做其他事情。但是时不时的来检查事件状态,也会带来不少的开销。于是就出现了异步非阻塞的事件处理机制,具体到系统调用就是像select/poll/epoll/kqueue这样的系统调用。它们提供一种机制,可以同时监控多个事件,调用它们是阻塞的,但是可以设置超时时间。在超时时间之内,如果有事件准备好了,就返回。以epoll为例,当事件没有准备好时,放到epoll里面,事件准备好了就去读写;当读写事件再准备的时候,再将事件加入到epoll里面。这样,只要有事件准备好了我们就去处理,只有当所有事件都没有准备好时,才在epoll里面等待。通过这种方法就能实现大量的并发了。由于只有一个线程,这里的并发是指在请求间不断的切换。这里的切换是因为异步事件未准备好而主动让出来的,这种切换是没有代价的。可以理解为循环处理多个准备好的事件。(这部分目前还没有完全理解。。。暂且几下,日后再调查)


与多线程模型相比

这种nginx的异步非阻塞的事件处理方式不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量。并发数再多也不会导致无谓的上线文切换那样的资源浪费。多并发数,只会占用多点内存而已。


参考资料:http://tengine.taobao.org/book/chapter_02.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值