深入剖析:基于epoll与主从Reactor模型的高性能服务器设计与实现

一.引言

时代背景​​:移动互联网、物联网时代下,海量连接与高并发请求成为常态。

**通信本质:**通信其实本是就是IO的过程,而对于IO而言,消耗最大的过程其实是等待的过程,假如一个对于单线程而说,如果一个链接一直不给你发消息,那么你会一直卡着对于这个链接的接收过程,

而epoll是基于事件驱动的,所以有了本文基于epoll的服务器设计。对于几种处理IO的方式我在之前的文章中介绍过可参考:C/C++ Select Poll Epoll 多路转接_c++ select epoll-CSDN博客

二.基石理论:深挖epoll与Reactor模式

Epoll底层使用的是红黑树+链表

相比Select和Poll的每次传回来所有事件,我们需要轮询所有事件达到O(N)的复杂度

而Epoll直接传回就绪事件,事件检测和通知的性能是O(1)。
Reactor模式:

一个Reactor 相当于一个一直在Loop的EventLoop

这个Reactor负责:

1.事件监听注册和事件处理注册

2.事件监听与处理

简单的一句话: 可以给Reactor注册一个需要被监听的事件,并给对应的事件就绪时注册对应的处理事件,当每次Reactor监听时,如果事件就绪就会执行对应的事件

三、架构设计:构建主从Reactor服务器骨架

1.Channel模块

本模块是对一个fd所对应事件操作的通道,简而言之,我们需要通过channel对一个fd所对应的某个事件进行操作,假如说如果需要设置某一个fd的可写事件的回调函数,我们需要通过对应的Channel来设置,假如说我们需要对该fd的可写事件进行监听,也是需要通过该组件的对应接口。

2.Buffer模块

该模块 处于 是对某个fd缓冲区 和 上层 业务层数据的 中间处设置缓冲区,作为底层数据到来和上层业务处理数据的缓冲, 上层业务通过该缓冲区的接口进行数据的放入和取出。

3.Socket模块

对Socket的进一步封装,简化操作,提供Server(create bind listen)和Client(create conncet)的各自的独特创建,提供设置是否阻塞模式,提供发送接收数据接口。

4.Acceptor

Acceptor可以看成一个特殊的Channel,负责创建监听fd的fd的事件进行管理。

管理对应的可读事件的监听以及对应回调函数的设置,

当可读事件触发意味着监听到新连接,触发对应的可读事件,以及对应的监听到新连接的事件回调。

5.Poller模块

Poller 正如命名一般,负责监听和管理监听事件。

而我们通过epoll进行监听,所以poller本质就是对epoll的封装,以及管理epoll进行监听的事件。若是我们需要对监听事件进行修改或增删,都是通过该接口进行操作。

6.TimerWheel

本模块是一个定时器模块,可以增加定时任务以及将一个任务刷新,即将一个快要结束的任务任务延后到下一个延迟时间。

7.EventLoop

EventLoop模块可以理解就是我们上边所说的Reactor模块,它是对Poller模块,TimerQueue模块, Socket模块的⼀个整体封装,进⾏所有描述符的事件监控。 EventLoop模块必然是⼀个对象对应⼀个线程的模块,线程内部的⽬的就是运⾏EventLoop的启动函 数。 EventLoop模块为了保证整个服务器的线程安全问题,因此要求使⽤者对于Connection的所有操作⼀ 定要在其对应的EventLoop线程内完成,不能在其他线程中进⾏(⽐如组件使⽤者使⽤Connection发 送数据,以及关闭连接这种操作)。
此外EventLoop采用 Poller+任务队列 的模式进行I/O事件的处理和任务的处理,为了防止Poller因为没有任务到来而阻塞,所以通过eventFd,来进行对Poller的唤醒以此来 执行任务队列。

7.Connection

Connection模块是对Buffer模块,Socket模块,Channel模块的⼀个整体封装,实现了对⼀个通信套 接字的整体的管理,每⼀个进⾏数据通信的套接字(也就是accept获取到的新连接)都会使⽤ Connection进行管理。

• Connection模块内部包含有三个由组件使用者传入的回调函数:连接建⽴完成回调,事件回调, 新数据回调,关闭回调。

• Connection模块内部包含有两个组件使用者提供的接口:数据发送接口;连接关闭接口

• Connection模块内部包含有两个用户态缓冲区:用户态接收缓冲区,用户态发送缓冲区

• Connection模块内部包含有⼀个Socket对象:完成描述符面向系统的IO操作

• Connection模块内部包含有⼀个Channel对象:完成描述符IO事件就绪的处理

四.总结

通过以上八大模块的协同工作,一个高性能、高并发的主从Reactor服务器骨架便得以建立。主Reactor负责高效接入新连接,从Reactor池负责处理已建立连接的I/O,线程池负责处理计算密集型业务,三者各司其职,共同支撑起百万级并发的服务能力

相关推荐
GilgameshJSS3 小时前
STM32H743-ARM例程15-RTC
c语言·arm开发·stm32·实时音视频
2301_803554523 小时前
C++联合体(Union)详解:与结构体的区别、联系与深度解析
java·c++·算法
初圣魔门首席弟子3 小时前
c++ bug 函数定义和声明不一致导致出bug
开发语言·c++·bug
bkspiderx4 小时前
C++设计模式之行为型模式:中介者模式(Mediator)
c++·设计模式·中介者模式
敢敢J的憨憨L4 小时前
GPTL(General Purpose Timing Library)使用教程
java·服务器·前端·c++·轻量级计时工具库
小欣加油4 小时前
leetcode 62 不同路径
c++·算法·leetcode·职场和发展
让我们一起加油好吗5 小时前
【C++】封装红黑树模拟实现 set 和 map
linux·c++·set·map·红黑树
hsjkdhs5 小时前
C++之类的继承与派生
开发语言·c++
冷徹 .5 小时前
2024ICPC区域赛香港站
数据结构·c++·算法