• Stars
    star
    501
  • Rank 88,002 (Top 2 %)
  • Language
    C++
  • License
    MIT License
  • Created over 7 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easy-Reactor是一个Linux C++高性能TCP服务框架,基于Reactor模式,支持单线程、多线程Reactor,也支持UDP服务

Easy Reactor

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 Event: 基于epoll

一切IO事件设置为非阻塞,由Linux epoll进行管理,且TCP、UDP的可读、可写事件均以默认方式即水平模式注册

为什么不用EPOLLET边缘触发模式?见我的文章:边缘模式的写事件(神坑!)

Timer Event: Timer Queue设计

  • 以最小堆管理Timers(注册Timer、删除Timer),以每个Timer的发生时间在最小堆中排序
  • 以timerfd作为通知方式,交给eventLoop监听,将超时事件转为IO事件
  • timerfd所设置的时间总是最小堆的堆顶Timer的发生时间

EventLoop

IO Event与Timer Event全部在EventLoop中注册、监听、运行,一个EventLoop独占一个线程

功能

对TCP服务器端: 支持设置:收到某类消息后回调函数,连接接收后回调函数,连接关闭前回调函数;

对TCP客户端: 支持设置:收到某类消息后回调函数,connect成功后回调函数,连接关闭前回调函数;

对UDP服务端、客户端: 都仅支持收到某类消息后回调函数

各服务端、客户端都可以主动发消息

此外,对多线程模式的TCP服务器 ,支持:向某个or ALL子线程发送待执行任务pendingTask回调函数,可以在一次poll循环后执行pendingTask内容

TCP服务器架构:多线程Reactor

Multi-Thread-Arch

多线程TCP服务器采用了one loop per thread模型(memcached、muduo也是这么干的)

主线程作为Accepter角色,线程池作为实际连接操作者TCPConnection,线程池每个线程运行EventLoop维护一定量的连接,管理这些连接的IO Event与Timer Event,线程池中每个线程初始时监听自己队列的eventfd,便于与主线程通信

Accepter细节

  1. Accepter收到新连接,以Round-Robin轮询方法将连接发送到一个线程的队列,以交给此线程管理这个连接
  2. Accepter已达连接上限时,使用占坑法处理
  3. Accepter使用大数组管理所有连接信息,当一个连接关闭,并不立即清理TCPConnection对象,而是等待新连接到来后复用此对象(memcached也是这么干的)

可写事件与busy loop

由于TCP socket写缓冲区总是准备好的(除非满了),如果一直监听EPOLLOUT事件会造成EventLoop产生busy loop现象,最严重会吃满CPU 故:

  • 有数据要写时,才监听EPOLLOUT;
  • 当所有数据已写到socket,立刻删除EPOLLOUT事件

粘包处理

使用固定长度包头8字节(4字节存放消息类型,4字节存放消息body长度),任何在Easy-Reactor中发送的消息都会被默默加上这个包头

消息分发

Server对象提供了:不同消息类型注册不同的回调函数功能,方便用户可以根据不同消息类型编写不同的处理函数 当读取socket数据后,如果包完整,则会根据消息类型ID,将一条 完整的消息 发给对应的回调函数去处理

缓冲区管理

每个连接对象TCPConnection没必要一直持有着读缓冲区和写缓冲区: 预设我们需要的一个缓冲区大小64KB,则每个连接需要读、写缓冲区共128KB -> 当连接数变多,内存占用过大

实际上

  • 对于读缓冲区,当读完全部数据且被处理后,读缓冲区就可以释放了,除非有粘包发生
  • 对于写缓冲区,当全部数据被发送到socket,写缓冲区就可以释放了,除非有数据没发完

我设计了一个简单的缓冲区管理容器,预先分配各种大小的缓冲区若干: 4K缓冲区:5000个,16KB:1000个,64KB:500个,256KB:200个,1MB:50个,4MB:10个

而每个TCPConnection初始时是没有读写缓冲区的,当需要读写时就向管理器索要一个长度合适的缓冲区使用,使用完就归还。具体而言:

每当TCPconnection读取数据:
  • 先会利用fcntl+FIONREAD获取可读数据大小
  • 如果有读缓冲区(说明上次粘包了,没归还),则看剩余缓冲区空间是否放得下新数据,能就放,不能就跟管理器要个新缓冲区替代了旧的,copy了旧缓冲区的数据后把旧的归还,把新可读数据放进来
  • 如果没有读缓冲区(说明上次没粘包,归还了),则跟管理器要个缓冲区,把新可读数据放进来
  • 当业务回调处理后发现缓冲区没更多数据了,归还;否则,将剩余数据移动到缓冲区头部,继续持有等待下次使用
每当TCPconnection写数据:
  • 用户调用sendData,如果有写缓冲区(说明上次每写完,不归还),则追加数据,如果放不下了,就跟管理器要个新缓冲区替代了旧的,copy了旧缓冲区的数据后把旧的归还,把新待发数据放进来
  • 一次性把写缓冲区的数据发送给socket后,如果发送完成,则归还缓冲区;否则把剩余待发数据移动到缓冲区头部,继续持有等待下次使用

UDP服务器架构:单线程Reactor

由于UDP是无连接的,多线程操作同一个UDP socket效率未必很高,故选择了单线程模型,图略因为很简单

使用者完全可以使用多线程,每个线程运行Easy-Reactor UDP服务器,即每个线程一个地址不同的UDP socket,可得到一定的并行能力

TCP、UDP客户端

都是eventLoop方式

使用方法

以一个TCP的pingpong echo server为例(具体TCP、UDP、timer例子见example目录)

tcp server端:

Server-Example

tcp client端:

Client-Example

More Repositories

1

Data-Structures-and-Algorithms-in-C

所有基础数据结构和算法的纯C语言实现,如各自排序、链表、栈、队列、各种树以及应用、图算法、字符串匹配算法、回溯、并查集等,献丑了
C
835
star
2

Ring-Log

Ring-Log是一个高效简洁的C++异步日志, 其特点是效率高(每秒支持至少125万+日志写入)、易拓展,尤其适用于频繁写日志的场景
C++
411
star
3

Netflix-Recommender-with-Spark

基于Apache Spark的Netflix电影的离线与实时推荐系统
Scala
247
star
4

My-Compiler-Designer

利用java语言写的编译器,自己设计了语言、文法、设计了词法分析、语法分析、语义分析和汇编代码生成
Java
122
star
5

Library-Manage-System

基于JSP struts2和hibernate3的 图书馆管理系统 包括读者和图书的基本管理和检索、排序
Java
68
star
6

Easy-Load-Balancer

Easy-Load-Balancer(ELB)是一个易用、稳定、高性能的服务间远程调用的管理、调度、负载系统
C++
57
star
7

sona

简单的、高可用、高效的基于共享内存的分布式配置中心,集中式管理各类后台配置,配置修改实时推送,且业务API相当简单(两行搞定,一个init+一个get,见readme),已轻量级支持Golang/C++/Java/Python等语言API
Go
39
star
8

KNN-Website-Classifier-System

一种基于改进的KNN网站分类系统,特点是快速、高准确率
Python
21
star
9

ekko-idgenerator

golang实现的分布式唯一ID生成器distributed id generator,有全局趋势递增、严防时钟漂移、高可用、高性能等特点
Go
11
star
10

Redis-StringCAS

Redis为String类型存储增加CAS操作, API包括getcas, getcas, and delcas
C
2
star