`
zy116494718
  • 浏览: 471224 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

nginx学习之epoll

阅读更多

首先说一下传统的I/O多路复用select和poll,对比一下和epoll之间的区别:

举个例子:假如有100万用户同时与一个进程保持TCP连接,而每一时刻只有几十或者几百个tcp连接是活跃的(即能接收到TCP包),那么在每一时刻进程只需要处理这100万连接中的有一小部分。

select和poll这样处理的:在某一时刻,进程收集所有的连接,其实这100万连接中大部分是没有时间发生的。因此,如果每次收集事件时,都把这100万连接的套接字传给操作系统(这首先就是用户态内存到内核内存的大量复制),而由操作系统内核寻找这些链接上没有处理的事件,将会是巨大的浪费。

而epoll是这样做的:epoll把select和poll分为了两个部分,

1、调用epoll_creat建立一个epoll对象。

2、调用epoll_ctl向epoll对象中添加这100万个连接的套接字。

3、调用epoll_wait收集发生事件的连接。=》重点是在这里,调用epoll_wait收集所有发生的事件的连接,并将事件放在一个链表中,这样只需到该链表中寻找发生连接的事件,而不用遍历100万连接!这样在实际收集事件时,epoll_wait效率会很高。


三个系统调用函数都是用C进行封装,在《深入理解Nginx》P310中由函数详细说明,下面简单介绍一下。

    int epoll_create(int size); 
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); 
    int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

首先要调用epoll_create建立一个epoll对象。参数size是内核保证能够正确处理的最大句柄数,多于这个最大数时内核可不保证效果。

epoll_ctl可以操作上面建立的epoll,例如,将刚建立的socket加入到epoll中让其监控,或者把 epoll正在监控的某个socket句柄移出epoll,不再监控它等等。

epoll_wait在调用时,在给定的timeout时间内,当在监控的所有句柄中有事件发生时,就返回用户态的进程。


那么epoll是如何实现以上想法的呢?

当某一个进程调用epoll_creat方法时,linux内核会创建一个eventpoll结构体,这个结构体中有两个成员的使用与epoll的使用方式密切相关。

    struct eventpoll {
        //红黑树的根节点,这棵树中存储着所有添加到epoll中的事件,也就是这个epoll监控的事件。
        struct rb_root rbr;
        //双向链表rdllist保存着将要通过epoll_wait返回给用户的、满足条件的事件。
        struct list_head rdllist;
    }


epoll为何如此高效:

当我们调用epoll_ctl往里塞入百万个句柄时,epoll_wait仍然可以飞快的返回,并有效的将发生事件的句柄给我们用户。这是由于我们在调用epoll_create时,内核除了帮我们在epoll文件系统里建了个file结点,在内核cache里建了个红黑树用于存储以后epoll_ctl传来的socket外,还会再建立一个list链表,用于存储准备就绪的事件,当epoll_wait调用时,仅仅观察这个list链表里有没有数据即可。有数据就返回,没有数据就sleep,等到timeout时间到后即使链表没数据也返回。所以,epoll_wait非常高效。


而且,通常情况下即使我们要监控百万计的句柄,大多一次也只返回很少量的准备就绪句柄而已,所以,epoll_wait仅需要从内核态copy少量的句柄到用户态而已,如何能不高效?!


那么,这个准备就绪list链表是怎么维护的呢?当我们执行epoll_ctl时,除了把socket放到epoll文件系统里file对象对应的红黑树上之外,还会给内核中断处理程序注册一个回调函数,告诉内核,如果这个句柄的中断到了,就把它放到准备就绪list链表里。所以,当一个socket上有数据到了,内核在把网卡上的数据copy到内核中后就来把socket插入到准备就绪链表里了。


如此,一颗红黑树,一张准备就绪句柄链表,少量的内核cache,就帮我们解决了大并发下的socket处理问题。执行epoll_create时,创建了红黑树和就绪链表,执行epoll_ctl时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上,然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据。执行epoll_wait时立刻返回准备就绪链表里的数据即可。


最后看看epoll独有的两种模式LT和ET。无论是LT和ET模式,都适用于以上所说的流程。区别是,LT模式下,只要一个句柄上的事件一次没有处理完,会在以后调用epoll_wait时次次返回这个句柄,而ET模式仅在第一次返回。


这件事怎么做到的呢?当一个socket句柄上有事件时,内核会把该句柄插入上面所说的准备就绪list链表,这时我们调用epoll_wait,会把准备就绪的socket拷贝到用户态内存,然后清空准备就绪list链表,最后,epoll_wait干了件事,就是检查这些socket,如果不是ET模式(就是LT模式的句柄了),并且这些socket上确实有未处理的事件时,又把该句柄放回到刚刚清空的准备就绪链表了。所以,非ET的句柄,只要它上面还有事件,epoll_wait每次都会返回。而ET模式的句柄,除非有新中断到,即使socket上的事件没有处理完,也是不会次次从epoll_wait返回的。

epoll的优点:

1.支持一个进程打开大数目的socket描述符(FD)

    select 最不能忍受的是一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的IM服务器来说显然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

 

2.IO效率不随FD数目增加而线性下降

    传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是"活跃"的,但是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个"伪"AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的---比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。

 

3.使用mmap加速内核与用户空间的消息传递

    这点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关注epoll的话,一定不会忘记手工 mmap这一步的。

 

4.内核微调

这一点其实不算epoll的优点了,而是整个linux平台的优点。也许你可以怀疑linux平台,但是你无法回避linux平台赋予你微调内核的能力。比如,内核TCP/IP协议栈使用内存池管理sk_buff结构,那么可以在运行时期动态调整这个内存pool(skb_head_pool)的大小--- 通过echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函数的第2个参数(TCP完成3次握手的数据包队列长度),也可以根据你平台内存大小动态调整。更甚至在一个数据包面数目巨大但同时每个数据包本身大小却很小的特殊系统上尝试最新的NAPI网卡驱动架构。

分享到:
评论

相关推荐

    实战Nginx_取代Apache的高性能Web服务器].张宴.扫描版

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、 CPU等系统资源消耗非常低,运行稳定。  本书系统地介绍了Nginx与PHP、RUBY、Python结合的使用方法,Nginx作为反向代理与负载均衡的配置与...

    实战Nginx:取代Apache的高性能Web服务器 中文版

    nginx选择了epoll和kqueue作为网络i/o模型,在高连接并发的情况下,内存、cpu等系统资源消耗非常低,运行稳定。  本书系统地介绍了nginx与php、ruby、python结合的使用方法,nginx作为反向代理与负载均衡的配置与...

    Nginx:取代apache的高性能服务器

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,Nginx是Apache服务器不错的替代品,它能够支持高达50 000个并发连接数的响应,运行稳定,且内存、CPU等系统资源消耗非常低。, 本书主要分为4个部分...

    nginx优化详细

    通过一个百万并发的nginx反向代理服务器的配置文件优化选项

    Nginx 1.22.0 Linux 版本,解压安装。

    在连接高并发的情况下,Nginx是Apache服务不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发...

    《实战Nginx:取代Apache的高性能Web服务器》PDF 下

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、CPU等系统资源消耗非常低,运行稳定。  本书系统地介绍了Nginx与PHP、RUBY、Python结合的使用方法,Nginx作为反向代理与负载均衡的配置与...

    实战Nginx:取代Apache的高性能Web服务器.part1.rar

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、CPU等系统资源消耗非常低,运行稳定。 本书系统地介绍了Nginx与PHP、RUBY、Python结合的使用方法,Nginx作为反向代理与负载均衡的配置与优化...

    实战Nginx:取代Apache的高性能Web服务器.part2.rar

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、CPU等系统资源消耗非常低,运行稳定。 本书系统地介绍了Nginx与PHP、RUBY、Python结合的使用方法,Nginx作为反向代理与负载均衡的配置与优化...

    [实战Nginx_取代Apache的高性能Web服务器].张宴.扫描版.part2

    Nginx选择了epoll和kqueue作为网络I/O模型,在高连接并发的情况下,内存、 CPU等系统资源消耗非常低,运行稳定。  本书系统地介绍了Nginx与PHP、RUBY、Python结合的使用方法,Nginx作为反向代理与负载均衡的配置与...

    nginx-1.18.0.zip

    Nginx是一个高性能的HTTP和反向代理服务器,...在Linux操作系统下,nginx使用epoll事件模型,得益于此,nginx在Linux操作系统下效率相当高。同时Nginx在OpenBSD或FreeBSD操作系统上采用类似于Epoll的高效事件模型kqueue.

    Nginx配置文件详细说明

    #epoll是多路复用IO(I/O Multiplexing)中的一种方式,但是仅用于linux2.6以上内核,可以大大提高nginx的性能 worker_connections 1024;#单个后台worker process进程的最大并发链接数 # multi_accept on; } ……...

    Nginx 1.22.0 Windows版本,解压安装。

    在连接高并发的情况下,Nginx是Apache服务不错的替代品:Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一。能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发...

    nginx-1.0.4 服务器软件下载

    能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发模型。  Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP...

    Nginx反向代理服务器

    能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发模型。 Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理...

    深入理解Nginx 模块开发与架构解析

    nginx作为一款开源的轻量级高性能web服务器,是非常值得立志从事服务端开发方向的人学习的。现今nginx的最新版本是nginx-1.13.6,代码量也日渐庞大,但是由于其核心思想并没改变,为了降低阅读难度,我选择的是nginx-...

    NginX VS2013工程

    没用GnuMake和Msys之类。 直接打开简单配置以下nginx_conf就能跑。 需要的第三方库已经包含了进去。 因为有一些系统函数windows实在没有,移植工作太耗费时间。 就直接把一些模块删掉了。 epoll和poll肯定是用...

    nginx-1.0.5.zip服务器

    能够支持高达 50,000 个并发连接数的响应,感谢Nginx为我们选择了 epoll and kqueue作为开发模型。 Nginx作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理...

    nginx源码浅析 1.4.0版本

    比较详细的分析了nginx关键源码,包括配置文件解析,进程模式,nginx epoll机制,http反向代理机制,http头读取

    nginx-1.14.0.tar.gz和nginx-1.14.0.zip(Linux和windows)

    能够支持高达 50,000 个并发连接数的响应,感谢 Nginx 为我们选择了 epoll and kqueue 作为开发模型. 作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。...

    nginx v1.5.9 for windows 源程序

    Nginx是一个很强大的高性能Web和反向代理服务器 它具有很多非常优越的特性 Nginx可以在大多数 Unix like OS 上编译运行 在Linux和unix上分别采用epoll和kqueue网络模型 能够支持高达 50 000 个并发连接数的响应...

Global site tag (gtag.js) - Google Analytics