Epoll工作模式详解----http://www.vimer.cn

转载 2012年03月23日 20:12:38

我们目前的网络模型大都是epoll的,因为epoll模型会比select模型性能高很多, 尤其在大连接数的情况下,作为后台开发人员需要理解其中的原因。

select/epoll的特点

select的特点:select 选择句柄的时候,是遍历所有句柄,也就是说句柄有事件响应时,select需要遍历所有句柄才能获取到哪些句柄有事件通知,因此效率是非常低。但是如果连接很少的情况下, select和epoll的LT触发模式相比, 性能上差别不大。
这里要多说一句,select支持的句柄数是有限制的, 同时只支持1024个,这个是句柄集合限制的,如果超过这个限制,很可能导致溢出,而且非常不容易发现问题, TAF就出现过这个问题, 调试了n天,才发现:)当然可以通过修改linux的socket内核调整这个参数。
epoll的特点:epoll对于句柄事件的选择不是遍历的,是事件响应的,就是句柄上事件来就马上选择出来,不需要遍历整个句柄链表,因此效率非常高,内核将句柄用红黑树保存的。
对于epoll而言还有ET和LT的区别,LT表示水平触发,ET表示边缘触发,两者在性能以及代码实现上差别也是非常大的。

epoll的LT和ET的区别

LT:水平触发,效率会低于ET触发,尤其在大并发,大流量的情况下。但是LT对代码编写要求比较低,不容易出现问题。LT模式服务编写上的表现是:只要有数据没有被获取,内核就不断通知你,因此不用担心事件丢失的情况。
ET:边缘触发,效率非常高,在并发,大流量的情况下,会比LT少很多epoll的系统调用,因此效率高。但是对编程要求高,需要细致的处理每个请求,否则容易发生丢失事件的情况。
下面举一个列子来说明LT和ET的区别(都是非阻塞模式,阻塞就不说了,效率太低):
采用LT模式下, 如果accept调用有返回就可以马上建立当前这个连接了,再epoll_wait等待下次通知,和select一样。
但是对于ET而言,如果accpet调用有返回,除了建立当前这个连接外,不能马上就epoll_wait还需要继续循环accpet,直到返回-1,且errno==EAGAIN,TAF里面的示例代码:

if(ev.events & EPOLLIN)
{
    do
    {
        struct sockaddr_in stSockAddr;
        socklen_t iSockAddrSize = sizeof(sockaddr_in);
        TC_Socket cs;
        cs.setOwner(false);
        //接收连接
        TC_Socket s;
        s.init(fd, false, AF_INET);
        int iRetCode = s.accept(cs, (struct sockaddr *) &stSockAddr, iSockAddrSize);
        if (iRetCode > 0)
        {
            ...建立连接
        }
        else
        {
            //直到发生EAGAIN才不继续accept
            if(errno == EAGAIN)
            {
                break;
            }
        }
    }while(true);
}

同样,recv/send等函数, 都需要到errno==EAGAIN

从本质上讲:与LT相比,ET模型是通过减少系统调用来达到提高并行效率的。

epoll ET详解

ET模型的逻辑:内核的读buffer有内核态主动变化时,内核会通知你, 无需再去mod。写事件是给用户使用的,最开始add之后,内核都不会通知你了,你可以强制写数据(直到EAGAIN或者实际字节数小于 需要写的字节数),当然你可以主动mod OUT,此时如果句柄可以写了(send buffer有空间),内核就通知你。
这里内核态主动的意思是:内核从网络接收了数据放入了读buffer(会通知用户IN事件,即用户可以recv数据)
并且这种通知只会通知一次,如果这次处理(recv)没有到刚才说的两种情况(EAGIN或者实际字节数小于 需要读写的字节数),则该事件会被丢弃,直到下次buffer发生变化。
与LT的差别就在这里体现,LT在这种情况下,事件不会丢弃,而是只要读buffer里面有数据可以让用户读,则不断的通知你。

另外对于ET而言,当然也不一定非send/recv到前面所述的结束条件才结束,用户可以自己随时控制,即用户可以在自己认为合适的时候去设置IN和OUT事件:
1 如果用户主动epoll_mod OUT事件,此时只要该句柄可以发送数据(发送buffer不满),则epoll
_wait就会响应(有时候采用该机制通知epoll_wai醒过来)。
2 如果用户主动epoll_mod IN事件,只要该句柄还有数据可以读,则epoll_wait会响应。
这种逻辑在普通的服务里面都不需要,可能在某些特殊的情况需要。 但是请注意,如果每次调用的时候都去epoll mod将显著降低效率,已经吃过几次亏了!

因此采用et写服务框架的时候,最简单的处理就是:
建立连接的时候epoll_add IN和OUT事件, 后面就不需要管了
每次read/write的时候,到两种情况下结束:
1 发生EAGAIN
2 read/write的实际字节数小于 需要读写的字节数
对于第二点需要注意两点:
A:如果是UDP服务,处理就不完全是这样,必须要recv到发生EAGAIN为止,否则就丢失事件了
因为UDP和TCP不同,是有边界的,每次接收一定是一个完整的UDP包,当然recv的buffer需要至少大于一个UDP包的大小
随便再说一下,一个UDP包到底应该多大?
对于internet,由于MTU的限制,UDP包的大小不要超过576个字节,否则容易被分包,对于公司的IDC环境,建议不要超过1472,否则也比较容易分包。

B 如果发送方发送完数据以后,就close连接,这个时候如果recv到数据是实际字节数小于读写字节数,根据开始所述就认为到EAGIN了从而直接返回,等待下一次事件,这样是有问题的,close事件丢失了!
因此如果依赖这种关闭逻辑的服务,必须接收数据到EAGIN为止,例如lb。



相关文章推荐

怎样把工作和升职大计结合起来 http://www.people.com.cn/GB/shenghuo/78/113/20020801/790056.html

怎样把工作和升职大计结合起来          别看当今媒体中长篇巨幅描写的都是所谓的“精英分子”,其实在各行各业中大多数是些勤勤恳恳...

委托模式(转自:http://www.uml.org.cn/j2ee/200411036.htm)

委托模式透明 选择自 www.c-view.org 梗概委托是对一个类的功能进行扩展和复用的方法。它的做法是:写一个附加的类提供附加的功能,并使用原来的类的实例提供原有的功能。 场景扩展和复用一个类的...

http://www.dataguru.cn/article-1602-1.html

R语言最好的IDE——RStudio 2012-7-2 22:30| 发布者: 仙豆| 查看: 26661| 评论: 8|原作者: rickey |来自: 沙湖王 摘要: ...

依赖倒置原则(DIP)转自:http://www.infoq.com/cn/articles/Implements-DIP-of-Web-Service

实现Web Service依赖倒置 作者 译者 王翔 发布于 2007年8月1日 下午10时49分 社区.NET主题设计,Web服务标签XML 问题的提出 作为面向对象设计的一...
  • wyh0318
  • wyh0318
  • 2012年07月11日 10:17
  • 694

在ASP.NET中动态加载内容 用户控件和模板(转http://www.da8848.cn/article/jiaocheng/NET/3838.html)

在ASP.NET中动态加载内容(用户组件和模板)要点:1. 使用Page.ParseControl2. 使用base.LoadControl第一部分:加载模板 下面是一个模板“...

借助开源工具高效完成Java应用的运行分析(转http://www.infoq.com/cn/articles/java-profiling-with-open-source)

作者 Joachim Haagen Skeie 译者 李勇 发布于 2011年11月9日 领域 语言 & 开发 主题 工具 , 性能和可伸缩性 , Java 标签 性能调优 , 开源...
  • fjfdszj
  • fjfdszj
  • 2011年11月09日 23:53
  • 521

实战 Jetty(转http://www.ibm.com/developerworks/cn/web/wa-lo-jetty/)

 周 登朋 (zhoudengpeng@yahoo.com.cn), 研究生, 上海交通大学周登朋,上海交通大学研究生,目前在IBM上海国际化实验室(SGL)实习。对Java技术,数据挖掘,信息检索技...
  • fjfdszj
  • fjfdszj
  • 2011年02月25日 11:01
  • 645

填报表用ajax实现关联单元格自动填充 http://www.quiee.com.cn/archives/3883/

在做填报表时,可能会遇到这样的需求,某个单元格值发生变化后,其他一些单元格值也跟着发生变化,就是局部刷新报表。如果是简单的加减乘除运算,可以在单元格的自动计算里面实现;如果关联单元格显示的内容是从数据...
  • xjmlyun
  • xjmlyun
  • 2012年07月06日 16:00
  • 359

extern及extern “C”用法 转自:http://www.cublog.cn/u/29619/showart_230148.html

extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字创意产品网 .它告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。1。对于extern变量来说,仅仅是一个变量的声明...
  • mm_lvw
  • mm_lvw
  • 2011年04月01日 22:05
  • 282

缓存(http://www.infoq.com/cn/articles/misunderstanding-using-cache-2)

缓存大量的数据集合,而读取其中一部分 在很多时候,我们往往会缓存一个对象的集合,但是,我们在读取的时候,只是每次读取其中一部分。 我们举个例子来说明这个问题(例子可能不是很恰当,但是足以说明...
  • tyb1222
  • tyb1222
  • 2012年05月30日 20:57
  • 487
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Epoll工作模式详解----http://www.vimer.cn
举报原因:
原因补充:

(最多只允许输入30个字)