epoll模型设计海量级连接服务器

本文深入探讨epoll模型在处理海量客户端连接的应用场景,对比select模型的优势,并介绍两种工作模式EdgeTriggered(ET)和LevelTriggered(LT),适用于高并发、高性能服务器设计。
最近在参与一个海量级(20000以上)远程连接的服务器设计,由于用户要求的硬件平台仅限于Linux,因此选择了epoll模型来实现对海量客户端连接的处理。
先聊一下epoll模型的基本情况。(一般来说,非海量级客户端连接的服务器,可能用不到epoll模型。一方面是由于epoll模型不能跨平台,另一方面初学者面露难色)。使用到epoll_create,epoll_ctl,epoll_wait,close 4个函数。
Epoll较之select优越的点,有两个方面:
1)select操作的socket对象的集合,要受到FD_SETSIZE的限制,各平台的缺省值也不一样(Windows上是64,AIX、Linux、HP、Solaris上为1024或2048不等);而epoll操作的socket对象集合仅受系统的句柄限制,一般来说,可以达到65535
2) select和epoll的核心实现机制不同。Select实现中,kernel每次都要遍历FD_SET中的socket,检测是否可读,花费的时间和FD_SET中的socket个数成正比;epoll实现中,当有socket可读时,由核心激活epoll订阅的一个事件,因此节省了sys cpu从而节约了资源,自然就提高了效率
epoll模型提供了二种工作模式:
1) Edge Triggered (ET)
ET是高速工作方式,只支持no-block socket。当IO事件发生时内核通知事件后不再发送更多的通知,直到用户执行的操作导致那个socket(或文件描述符)事件的改变,也就是说如果用户不对socket(或文件描述符)进行IO操作,那么内核也不会再通知事件。
2) Level Triggered (LT)
LT是缺省的工作方式,同时支持block和no-block socket。内核通知事件一个文件描述符是否就绪了,然后可以对这个就绪的fd进行IO操作。如果用户不作任何读、写操作,内核还是会继续通知事件的。
更详细的epoll定义或信息,参照相关网络信息或书籍即可。下面,我来描述一下,这个需求中的epoll模型的设计。
一、业务需求如下图,要求满足高并发、高性能、高可靠等属性。
epoll模型设计海量级连接服务器



二、流程设计:
1) 主进程
epoll模型设计海量级连接服务器


1) Net_recv_thfunc工作线程


epoll模型设计海量级连接服务器

Handle_NetRecv函数流程

epoll模型设计海量级连接服务器


2) Net_send_thfunc工作线程

epoll模型设计海量级连接服务器
Epoll模型使用中,注意以下几个点:
1)避免多个线程操作同一个epoll对象,否则会出现惊群现象,即当一个可读EPOLLIN或EPOLLOUT事件到达时,所有线程都返回这个事件,但只有一个线程真正能拿到这个事件,其他的线程将返回EWOULDBLOCK
2)操作epoll对象的线程和操作socket的线程是否分开,应视后续的处理效率而定。如果接受到socket数据的后续处理性能高,则可以在同一线程里来搞定;否则,需要创建另一类线程池,来参与socket数据的后续处理。
3)毕竟,一个进程内的句柄数也有限。如果要适应更加海量的客户端连接,可采取在同一台设备(硬件资源足够的情况下)或多台设备上,部署多套“接入管理Server”。
### 比较Linux中的poll模型epoll模型 #### 功能概述 在Linux操作系统中,`poll()` 和 `epoll()` 都用于实现I/O多路复用功能。这两种机制允许程序监视多个文件描述符的状态变化,从而有效地管理并发连接。 对于 `poll()` 函数而言,在每次调用时都需要传递整个感兴趣的文件描述列表给内核,并且当有事件发生时返回这些文件描述符的一个子集[^2]。而相比之下,`epoll_create()` 创建一个新的 epoll 实例之后可以通过 `epoll_ctl()` 来注册或移除关注的文件描述符,这使得操作更加灵活高效[^1]。 #### 性能差异 - **效率方面** - 使用 `poll()` 进行轮询时,即使没有任何就绪的文件描述符也会遍历全部集合来查找是否有新的活动情况;而在高负载情况下这种做法会带来较大的开销。 - 反之,一旦通过 `epoll_ctl()` 添加到监控队列里的文件描述符发生变化,则对应的回调会被触发并立即通知应用程序层处理相应事务——这意味着只有真正发生了变动的地方才会被访问,极大地提高了响应速度和资源利用率。 - **扩展性考量** - 当监听大量套接字时,由于 `poll()` 的线性扫描特性使其性能随数量增加呈指数下降; - 而基于红黑树结构优化过的 `epoll()` 则能够很好地应对大规模网络请求场景下的快速检索需求,支持更高的并发量而不影响整体表现。 #### 应用场景分析 - 对于小型应用或者服务器端口数较少的情况来说,采用传统的 `poll()` 或者更早版本的选择器如 `select()` 已经可以满足基本的需求。 - 如果涉及到高性能Web服务、即时通讯工具以及其他需要处理海量短链接的任务时,则推荐选用更为先进的 `epoll()` 接口以获得更好的吞吐能力和更低延迟的服务质量保障。 ```c // 示例代码展示如何创建一个简单的Epoll实例 #include <sys/epoll.h> #include <unistd.h> #define MAX_EVENTS 10 int main(void){ int nfds; struct epoll_event ev, events[MAX_EVENTS]; int epfd = epoll_create1(EPOLL_CLOEXEC); // 假设这里已经绑定了某些socket fd... while (1) { nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); for(int n = 0; n < nfds; ++n){ // 处理events[n].data.fd上的IO事件 } } close(epfd); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值