http://hi.baidu.com/netpet/blog/item/2cc79216d9012b54f2de32b9.htmlhtml
前段时间将新的web模型办到linux上来,用epoll代替了IOCP,经测试确实性能提升了不少,吞吐量也寓所提升,对于linux下面的网络编程不是三言两语就能说得透的了,加上多线程就更麻烦了,可是epoll模型的精髓就是事件驱动,这种模型提供了保持链接socket直线增涨而性能不会直线降低的特性,纵观epoll kueuen select等等,全部都是在解决一个socket不须要一个线程的问题,将事件去分开来
在ningx(有人用他同时保持了3万个处理链接)上的到了一些体会,这些不只使用于web这样模型的server,一样适合于全部其余的好比游戏、ftp服务器等。
维持高在线人数的关键问题在于事件处理模型须要m:n,m远<n, m为socket,n为链接socket,无论你有多少个cpu(好比2cpu 4核),计算机能同时处理的线程数都是不多的,socket的关键在于网络等IO的延迟,若是让线程堵塞在一个网络IO上那全部的基础优化算法都是白搭,由于算法的不佳只能影想很短的时间,可是网络IO延迟就很难讲了,有位前辈说了很好的一句话:作多服务器网络协做程序任什么时候候记住减小一次路由比优化100次一个算法都划算。
nginx的作法是将处理程序严格区分开来(本次我做的Flower web server也是基于此原理),等待epoll等事件通知,他在全局范围内维护了两个链表,一个读连表,一个写链表,epoll等系统网络通知通知了某个socket可操做后他便将状态保存在相应的变量里面,而后采起m个线程轮询执行任务,这样线程就不用等待网络io堵塞,正常的一个read socket数据须要循环,直到数据读完或者产生错误,但个人处理不是这样的,我在全局范围内维护一个统一的socket fd表,这是linux的特性决定的,由于linux的socket fd是从很小的值开始的,而且同一时间内不会重复(估计内部有线程锁),全部fd自己就是一个重要的标识量,而且一个大的fd释放后还会从小的开始重复利用,winsows下的就不同,他是一个长长的指针,全部个人全局状态表就须要一个用fd做为索引的标识就能够了,最大的fd也就是同时保持在线人数的大致数字,我设置了一个20000的状态表,暂用栈内存很小,基本上不会被用完。
而后我一样对read和write设置两个独立的状态链表,用m个线程来处理,所不一样的是这两个表只有一个fd项,其他的数据都是保存在堆分配的全局状态表中,我对全局状态表设置不少的状态值,好比:read write readed writed needRepetRead needrepetWrite restart等等,这样我能够将其余的处理分别用新的状态链表来保持,锁不一样的是全局表的状态不同,从而达到多个处理程序协做的问题,互斥锁只存在于各个处理环节,若是读的环节慢了就能够加大读的线程数,写的慢了能够加大写的,处理的过程慢了能够加大处理的,这样方便系统后期调试优化,可是每个环节都不会影响全局表的处理,不会由于一个线程堵塞或则死掉致使全局的状态都无法进行
初步做出来的模型一样采用sendfile +epoll状况下,经测试个人server已经略微超过nginx,下面就是进一步的规范和优化扩展的部分了linux
我也是刚刚转到linux下面来,polled,select是早期的两个模型,总的来讲这个种都是为了到达到事件通知功能,内部实现原理不同,因此在实际应用的过程当中就能够作这样的分层:事件模型和协议处理模型分开。有不少这样的例子,nginx就是这样的,编译的时候根据不一样的系统选择不一样的事件通知模型,也就是说你写的程序觉大部分跟这几个函数不要紧,他们只是起到检测socket事件的做用,至于内部区别你能够去看源代码,也有网上的大量说明,不必这里再细细罗列,目前epoll在处理大量用户链接的状况下综合性能最好,少许链接(1-200个)就都差很少了,甚至pool或者select比epoll还好,这是他们实现的机制不一样nginx
Reference:web
epoll为何这么快 http://www.cppblog.com/converse/archive/2008/10/12/63836.html算法