Easy-Reactor是一个基于Reactor模式的Linux C++网络服务器框架,支持多线程TCP服务器,单线程TCP服务器,单线程UDP服务器等形式,可以让使用者完全专注于业务,快速开发出一个高效的服务器应用。
在工作中开发基础服务器的经验总结、以及阅读陈硕《muduo》一书的收获,使得我以沉淀的心态做了这个项目
此项目在我的另一个项目易用稳定、高性能的服务间远程调用管理、调度、负载系统:Easy-Load-Balancer中得到了全面应用,此项目的实战充分证明了Easy-Reactor服务框架的性能很高、使用也很简单
服务器参数: CPU个数:24 内存:128GB 网卡队列个数:24
测试程序: echo pingpong服务,每次传递100字节内容,见目录test/
TCP服务线程数 | benchmark情况 | QPS |
---|---|---|
1线程 | 5个benchmark,各建立100个连接 | 10.96W/s |
3线程 | 5个benchmark,各建立100个连接 | 31.06W/s |
5线程 | 5个benchmark,各建立100个连接 | 48.12W/s |
8线程 | 9个benchmark,各建立100个连接 | 59.79W/s |
一切IO事件设置为非阻塞,由Linux epoll进行管理,且TCP、UDP的可读、可写事件均以默认方式即水平模式注册
为什么不用EPOLLET边缘触发模式?见我的文章:边缘模式的写事件(神坑!)
IO Event与Timer Event全部在EventLoop中注册、监听、运行,一个EventLoop独占一个线程
对TCP服务器端: 支持设置:收到某类消息后回调函数,连接接收后回调函数,连接关闭前回调函数;
对TCP客户端: 支持设置:收到某类消息后回调函数,connect成功后回调函数,连接关闭前回调函数;
对UDP服务端、客户端: 都仅支持收到某类消息后回调函数
各服务端、客户端都可以主动发消息
此外,对多线程模式的TCP服务器 ,支持:向某个or ALL子线程发送待执行任务pendingTask回调函数,可以在一次poll循环后执行pendingTask内容
多线程TCP服务器采用了one loop per thread模型(memcached、muduo也是这么干的)
主线程作为Accepter角色,线程池作为实际连接操作者TCPConnection,线程池每个线程运行EventLoop维护一定量的连接,管理这些连接的IO Event与Timer Event,线程池中每个线程初始时监听自己队列的eventfd,便于与主线程通信
由于TCP socket写缓冲区总是准备好的(除非满了),如果一直监听EPOLLOUT事件会造成EventLoop产生busy loop现象,最严重会吃满CPU 故:
使用固定长度包头8字节(4字节存放消息类型,4字节存放消息body长度),任何在Easy-Reactor中发送的消息都会被默默加上这个包头
Server对象提供了:不同消息类型注册不同的回调函数功能,方便用户可以根据不同消息类型编写不同的处理函数 当读取socket数据后,如果包完整,则会根据消息类型ID,将一条 完整的消息 发给对应的回调函数去处理
每个连接对象TCPConnection没必要一直持有着读缓冲区和写缓冲区: 预设我们需要的一个缓冲区大小64KB,则每个连接需要读、写缓冲区共128KB -> 当连接数变多,内存占用过大
实际上
我设计了一个简单的缓冲区管理容器,预先分配各种大小的缓冲区若干: 4K缓冲区:5000个,16KB:1000个,64KB:500个,256KB:200个,1MB:50个,4MB:10个
而每个TCPConnection初始时是没有读写缓冲区的,当需要读写时就向管理器索要一个长度合适的缓冲区使用,使用完就归还。具体而言:
fcntl+FIONREAD
获取可读数据大小由于UDP是无连接的,多线程操作同一个UDP socket效率未必很高,故选择了单线程模型,图略因为很简单
使用者完全可以使用多线程,每个线程运行Easy-Reactor UDP服务器,即每个线程一个地址不同的UDP socket,可得到一定的并行能力
都是eventLoop方式
以一个TCP的pingpong echo server
为例(具体TCP、UDP、timer例子见example目录)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。