From:http://tengine.taobao.org/book/chapter_02.html

  上篇文章讲了很多关于nginx的进程模型,接下来,我们来看看nginx的是如何处理事件的。

  有人可能要问了,nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个worker就 能处理多少个并发,何来高并发呢?非也,这就是nginx的高明之处,nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理 成千上万个请求的。想想apache的常用工作方式(apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个请求会独占一个工作线程,当并发数上到几千时,就同时有几千的线程在处理请求了。这对操作系统来说,是个不小的挑战,线程带来的内存占用非常大,线程的上下文切换带来的 cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。

  为什么nginx可以采用异步非阻塞的方式来处理呢,或者异步非阻塞到底是怎么回事呢?我们先回到原点,看看一个请求的完整过程。首先,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧。阻塞调用会进入内核等待,CPU就空闲了(原文:cpu就会让出去给别人用了),对单线程的 worker来说,显然不合适,当网络事件越多时,大家都在等待呢,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了。好吧,你说加进程 数,这跟apache的线程模型有什么区别,注意,别增加无谓的上下文切换 ?所以,在nginx里面,最忌讳阻塞的系统调用了。不要阻塞,那就非阻塞喽。非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好呢,你慌什么,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的。所以,才会有了异步非阻塞的事件处理机制,具体到系统 调用就是像select/poll/epoll/kqueue这样的系统调用。它们提供了一种机制,让你可以同时监控多个事件,调用他们是阻塞的,但可以设置超时时间,在超时时间之内,如果有事件准备好了,就返回。这种机制正好解决了我们上面的两个问题,拿epoll为例(在后面的例子中,我们多以 epoll为例子,以代表这一类函数),当事件没准备好时,放到epoll里面,事件准备好了,我们就去读写,当读写返回EAGAIN时,我们将它再次加入到epoll里面。这样,只要有事件准备好了,我们就去处理它,只有当所有事件都没准备好时,才在epoll里面等着。这样,我们就可以并发处理大量的 并发了,当然,这里的并发请求,是指未处理完的请求,线程只有一个,所以同时能处理的请求当然只有一个了,只是在请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的。这里的切换是没有任何代价,你可以理解为循环处理多个准备好的事件,事实上就是这样的。与多线程相比,这种事件处理方式 是有很大的优势的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。更多的并发数,只是会占用更多的内存而已。 我之前有对连接数进行过测试,在24G内存的机器上,处理的并发请求数达到过200万。现在的网络服务器基本都采用这种方式,这也是nginx性能高效的 主要原因。

  我们之前说过,推荐设置worker的个数为cpu的核数,在这里就很容易理解了,更多的worker数,只会导致进程来竞争cpu资源了,从而带来不必要的上下文切换。而且,nginx为了更好的利用多核特性,提供了cpu亲缘性的绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。像这种小的优化在nginx中非常常见,同时也说明了nginx作者的苦心孤诣。比如,nginx在做4个字节的字符串比较时, 会将4个字符转换成一个int型,再作比较,以减少cpu的指令数等等。

  现在,知道了nginx什么会选择这样的进程模型与事件模型了。对于一个基本的web服务器来说,事件通常有三种类型,网络事件、信号、定时器。从上面的讲解中知道,网络事件通过异步非阻塞可以很好的解决掉。如何处理信号与定时器?

  首 先,信号的处理。对nginx来说,有一些特定的信号,代表着特定的意义。信号会中断掉程序当前的运行,在改变状态后,继续执行。如果是系统调用,则可能 会导致系统调用的失败,需要重入。关于信号的处理,大家可以学习一些专业书籍,这里不多说。对于nginx来说,如果nginx正在等待事件 (epoll_wait时),如果程序收到信号,在信号处理函数处理完后,epoll_wait会返回错误,然后程序可再次进入epoll_wait调 用。

  另外,再来看看定时器。由于epoll_wait等函数在调用的时候是可以设置一个超时时间的,所以nginx借助这个超时时间来实现定时器。nginx里面的定时器事件是放在一个最小堆里面,每次在进入epoll_wait前,先从最小堆里面拿到所有定时器事件的最小时间,在计算出epoll_wait的超时时间后进入epoll_wait。所以,当没有事件产生,也没有中断信号时,epoll_wait会超时,也就是说,定时器事件到了。这时,nginx会检查所有的超时事件,将他们的状态设置为超时,然后再去处理网络事件。由此可以看出,当我们写nginx代码时,在处理网络事件的回调函数时,通常做的第一个事情就是判断超时,然后再去处理网络事件。

我们可以用一段伪代码来总结一下nginx的事件处理模型:

while (true) {
for t in run_tasks:
t.handler();
update_time(&now);
timeout = ETERNITY;
for t in wait_tasks: /* sorted already */
if (t.time <= now) {
t.timeout_handler();
} else {
timeout = t.time - now;
break;
}
nevents = poll_function(events, timeout);
for i in nevents:
task t;
if (events[i].type == READ) {
t.handler = read_handler;
} else (events[i].type == WRITE) {
t.handler = write_handler;
}
run_tasks_add(t);
}

好,本节我们讲了进程模型,事件模型,包括网络事件,信号,定时器事件。

转:初探nginx架构(二)的更多相关文章

  1. 转:初探nginx架构(一)

    来源:http://tengine.taobao.org/book/chapter_02.html 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢? ...

  2. 初探Nginx架构

    参考链接:http://tengine.taobao.org/book/chapter_02.html nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个maste ...

  3. 初探 Nginx 架构

    转载自:http://wiki.jikexueyuan.com/project/nginx/nginx-framework.html Nginx 在启动后,在 unix 系统中会以 daemon 的方 ...

  4. Nginx架构的企业级应用

    Nginx架构的企业级应用 ==================================================== 实现HA高可用集群 实现LB负载均衡集群 Nginx实现反向代理 ...

  5. nginx实战二

    nginx架构分析 1.nginx模块化 Nginx涉及到的模块分为核心模块.标准HTTP模块.可选HTTP模块.邮件服务模块以及第三方模块等五大类. https://coding.net/u/ami ...

  6. 初探JavaScript(二)——JS如何动态操控HTML

    除去五一三天,我已经和<JavaScript Dom编程艺术>磨合了六天,第一印象很好.慢慢的,我发现这是一块排骨,除了肉还有骨头.遇到不解的地方就会多看几遍,实在不懂的先跳过,毕竟,初次 ...

  7. Nginx学习笔记(一) Nginx架构

    Nginx架构 Nginx全程是什么? Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器. ...

  8. [转载] 深入 nginx 架构

    原文: http://www.cnbeta.com/articles/402709.htm 了解 nginx 架构帮助我们学习如何开发高性能 web 服务. 为了更好地理解设计,你需要了解NGINX是 ...

  9. Nginx教程(二) Nginx虚拟主机配置

    Nginx教程(二) Nginx虚拟主机配置 1 虚拟主机管理 1.1 Nginx管理虚拟主机 虚拟主机使用的是特殊的软硬件技术,它把一台运行在因特网上的服务器主机分成一台台“虚拟”的主机,每台虚拟主 ...

随机推荐

  1. EBS已安装模块

    /* Formatted on 2018/3/15 11:14:51 (QP5 v5.256.13226.35538) */ SELECT fa.application_short_name , fp ...

  2. 【转】比较init-method,afterPropertiesSet和BeanPostProcessor

    一.简单介绍 1.init-method方法,初始化bean的时候执行,可以针对某个具体的bean进行配置.init-method需要在applicationContext.xml配置文档中bean的 ...

  3. hbase经常使用的shell命令样例

    1.hbase shell    进入hbase [hadoop@mdw ~]$ hbase shell HBase Shell; enter 'help<RETURN>' for lis ...

  4. JAVA使用Marvin在图片中搜索图片

    Java对图像的处理框架比较少,目前比较流行的有Jmagick以及Marvin,但Jmagick只能处理图像(上篇Java清除图片中的恶意信息(利用Jmagick)中对Jmagick已做过简略介绍), ...

  5. mysql中文显示问号,不能识别中文的解决方案

    到后台mysql中查看是问号. 并不能显示出中文,初步判定是编码的问题. 我们利用 show variables like'character_set_%'; 与 show variables lik ...

  6. linux下vi操作Found a swap file by the name

    当我在linux下用vi打开Test.java文件时 [root@localhost tmp]# vi Test.java 会出现如下信息: E325: ATTENTION Found a swap  ...

  7. SRE学习笔记:分布式共识系统、Paxos协议

    最近阅读了<SRE Google运维解密>的第23章,有一些感触,记录一下. 日常工作中,我们经常需要一些服务分布式的运行.跨区域如跨城.跨洲部署运行分布式系统往往是容易的,但是如何保证各 ...

  8. information_schema系列十

    information_schema系列十   1:INNODB_FT_CONFIG 这张表存的是全文索引的信息,查询前可以先通过以下语句查询一下开启全文索引的表: show variables li ...

  9. [转]ThinkPHP中如何使用原生SQL

    From : http://huangqiqing123.iteye.com/blog/1540323 TP的模型可以支持原生SQL操作,提供了query和execute两个方法,为什么原生SQL还要 ...

  10. 几个常用linux命令语句

    几个常用linux命令 英文原文:What are the most useful "Swiss army knife" one-liners on Unix? 下面的这些内容是 ...