深入剖析:基于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,线程池负责处理计算密集型业务,三者各司其职,共同支撑起百万级并发的服务能力

相关推荐
wu_asia3 分钟前
编程技巧:如何高效输出特定倍数数列
c语言·数据结构·算法
清 澜10 分钟前
c++高频知识点总结 第 1 章:语言基础与预处理
c++·人工智能·面试
你怎么知道我是队长14 分钟前
C语言---无名位域
c语言·开发语言
fqbqrr29 分钟前
2601C++,模块基础
c++
带土129 分钟前
6. C++智能指针(1)
开发语言·c++
星火开发设计41 分钟前
C++ queue 全面解析与实战指南
java·开发语言·数据结构·c++·学习·知识·队列
橘颂TA1 小时前
【剑斩OFFER】算法的暴力美学——力扣 394 题:字符串解码
数据结构·c++·结构与算法
txinyu的博客2 小时前
结合游戏场景理解,互斥锁,读写锁,自旋锁,CAS / 原子变量,分段锁
开发语言·c++·游戏
hugerat2 小时前
在AI的帮助下,用C++构造微型http server
linux·c++·人工智能·http·嵌入式·嵌入式linux
-森屿安年-2 小时前
unordered_map 和 unordered_set 的实现
数据结构·c++·散列表