当前位置: 首页 > news >正文

基于主从Reactor模式的高性能服务器

服务器性能

百万并发2核2G 2M Linux云服务器2线程100并发请求,持续1000s,达到百万连接处理且0错误

 

高并发HTTP服务器项目:性能与功能性测试汇总-CSDN博客(测试详细信息)

主要通信逻辑分析

初始化与启动主从Reactor

  • TcpServer初始化,也就是构造的时候,会创建Acceptor、EventLoop、LoopThreadLoop
  • Acceptor开始监听端口,这个监听类只为主Reactor服务,其他Reactor不可用
  • LoopThreadPoll,创建多个线程,并给每一个线程都分配一个EventLoop,也就是服务器的核心,一个线程一个的Reactor

接受新连接

  • 新连接到达服务端后,Accept触发读事件,然后调用Accept的回调函数,创建新连接对象 
  • 创建的新连接交给主Reactor的EventLoop进行管理
    • 超时,则时间轮上的定时器对该连接进行销毁
    • 可读,则掉员工Channl,利用其回调函数,唤醒线程池中的一个子Reactor
  • 子Reactor唤醒后,该处是轮询,避免某一个Reactor负载过重,然后开始执行监听处理该连接的逻辑

 

 子Reactor处理逻辑

  • Poller监控连接文件描述符上的事件是否发生
  • 事件发生通知EventLoop,然后EventLoop调用Channel进行处理
  • Channel与Connection中功能以及缓冲区模块相结合,利用事先设置好的回调函数,完成数据的发送

项目技术架构与设计思路

首先叙述一下选择该架构的原因,以及自己对该架构相应的理解

Reactor就是一种事件驱动模型,利用I/O复用机制去监听事件,事件响应后就进行处理,项目刚建立时使用单Reactor模式,但是在面对高并发请求的时候,表现仍旧不是很出色。

经学习mudou网络库的主要思想后,项目该成主从Reactor模式,在一个进程下,一个线程一个Reactor,且主Reactor只负责接收新连接,然后通过轮询交给子Reactor去处理业务,利用该方式从而可以高效的处理并发请求。

HTTPServer改进思路2(mudou库核心思想融入)-CSDN博客(详细理解以及改进思路参考该文章)

选择主从Reactor模式实现高并发的原因,主要因为在该模式下,可以有效的分离连接请求以及事务处理逻辑,避免单个Reactor过载的情况

与此同时,这种模式是利用的多线程并行处理事件,不像多线程运行需要来回切换,消耗服务器性能,利用多线程显著的提高系统的吞吐量和响应速度,非常适合在高并发场景下使用。

One Loop Per One Thread服务器通信逻辑梳理-CSDN博客(该问详细解释了服务器的具体通信逻辑)

其次说明一下项目中对于多线程管理的思路

使用一个线程一个Reactor这种设计规则,优点很明显。使用该模式,每个线程都有一个自己的Reactor,这样就不需要竞争锁,所以减少了性能消耗,提高服务器的并发处理效率

与此同时极大简化了线程间的通信,因为每个线程只需要处理自己负责的事件,准确来说,只有主线程需要和子线程进行通信,其他子线程只负责干活就行了,不需要与其他线程通信。

但是避免不了会出现相应的问题,首先是需要处理如何分配新连接给从Reactor,以达到平衡负载,如果设计不当的话则会导致某个Reactor负载过重,而导致整体程序崩溃。

其次就是需要处理线程的生命周期,同时还要处理出现错误的线程,确保整个系统运行的稳定性。

主Reactor与其他Reactor通信逻辑分析

项目设计中,主Reactor使用了一个线程池管理从Reactor线程,通过事件通知机制,本项目中采用了evendfd,从而实现主从Reactor之间的通信。通过该方式,也就实现了最终目的,主Reactor接收新连接,然后通过eventfd唤醒子Reactor处理连接。 

多个子Reactor管理问题说明

本项目设计中,每一个Reactor都由一个线程专门管理,所以会有非常多线程在进程下运行,如果管理不当,随时会导致程序的崩溃。本项目将这些线程都放在线程池中进行统一管理

线程池在启动的时候就会创建一组线程待命,每个线程都有一个事件循环,以及处理文件描述符的CHannel。而全部线程生命周期是由线程池进行管理的,所以创建销毁以及错误,都是线程池进行管理。最后通过条件变量以及互斥锁管理线程的工作和休眠状态。 

任务池设计

主从Reactor都有自己的任务池,主Reactor任务池则是一群Reactor等待新连接,而子Reactor的任务池则是定时任务和一些耗时的I/O事件或者待释放的事件。借助任务池的设计,从而实现任务延迟执行(避免某些连接阻塞太久导致后续的任务无法执行)线程安全(主从Reactor之间的传递信息的线程安全)以及任务合并处理

主从Reactor模式 任务池提高请求处理效率分析-CSDN博客

最后说明一下项目的模块设计

为了增强项目中每个模块的独立性以及后期维护性,主要做了以下几种设计。

首先是规定了每个模块的职责,同时使用接口和回调进行通信。模块内部的实现细节对外全部隐藏,目的就是保证模块运行的独立性。

其次,在书写各个模块的时候,使用谷歌单元测试工具以及自主实现功能代码,对各个模块的功能进行了测试,确保后续的维护性。

最后,项目还是拆解成各个模块,例如项目中对网络模块、定时器模块、文件描述符处理模块都进行了单独的拆分。这些模块通过接口进行通信,避免模块之间的直接依赖,也实现了最终的解耦合。

C++ bind复杂回调逻辑分析-CSDN博客(项目中回调函数逻辑分析)

组件搭建HTTP服务器思路总结

项目的重点不是HTTP请求处理上,而是可以实现搭建高并发服务器的组件,该处HTTP服务器的构建,目的只是测试组件高并发的性能,其他具体业务场景并没有进行实现。以后在该处拓展的地方可以有很多。

首先简述一下HTTP协议在项目中的处理

项目中对于HTTP请求处理的步骤,首先是对请求进行解析 ,解析请求行,提取方法、路径、协议版本,然后逐行解析头部字段最后读取正文。然后根据请求响应即可,项目中并没有具体的业务处理场景。

项目中使用正则表达式匹配来优化性能,首先是通过预编译正则表达式来提高匹配效率,避免每次匹配的时候都进行编译,从而提高性能。

其次分析该服务器的性能

对于服务器中性能的优化点,也就是上述主从Reactor服务器的性能优点,因为HTTP服务器就是使用该思想构建实现的,所以拥有主从Reactor服务器的所有优点。

错误处理以及项目中遇到难点及解决思路

项目中错误处理机制

大量请求的时候,如果请求出现错误,则可能会影响服务器运行的稳定性。服务器既然要实现高并发,那稳定肯定也是必须的,所以为了错误请求不抛出异常,于是项目中将所有出现的错误都返回错误码或者生成的错误响应 方式进行处理。

服务器是多线程环境,所以要保证错误处理也是线程安全的。具体实现方法就是,将错误处理逻辑就固定在特定线程内,不让其他线程看到该错误,也就是说避免多个线程同时处理同一错误,导致服务器出现错误。

但是如果出现网络异常导致的连接中断,这种就需要设计异常处理机制了,根据捕捉的异常类型,决定是重新连接还是断开该连接。

高并发服务器项目:内存管理实现逻辑-CSDN博客(智能指针与RAII机制在项目中的应用)

 日志系统的构建

项目中自主实现了日志系统,该日志系统的主要目的就是对服务器运行期间出现的问题进行排查,同时还能够对运行逻辑进行观察。 

定时任务与时间轮

Linux定时器与时间轮 实现网络连接超时关闭-CSDN博客 (具体实现解析)

时间轮就是将定时任务按照时间分配到时间槽中,每个槽中都有对应任务,通过模拟时间的流逝,逐个运行时间槽中的任务,特别适合大量定时任务的管理和处理

使用时间轮管理任务的主要目的,是对长时间无操作的连接进行管理,避免无效连接占用计算机资源,导致资源泄漏。同时还能够指定定时任务,该项目中是使用其处理超时销毁任务。

最后总结一下自己制作该项目的一下问题

首先项目构建最大的难点在于如何实现高并发处理机制,以及内存如何管理才能避免内存泄漏还有在网络连接过程中,如何处理哪些错误连接,这三点也是项目的最大难点。

第一引入了主从Reactor模式和线程池,解决高并发处理问题第二通过使用内存管理和缓冲区,减少了内存使用次数以及拷贝频率第三则是通过错误处理机制以及日志系统保证系统的安全性。

项目未来的改进方向,首先可以使用更好的并发编程模型,比如协程,更进一步的提高并发能力,同时可以引用HTTP2以及HTTPS,增加传输效率的同时可以增加安全性。也可以优化日志系统和监控服务器工具,后期问题也可以更好的进行维护。 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【视频讲解】Python灰色关联度分析直播带货效用、神经退行性疾病数据
  • 数字**笔试题--链表翻转与list排序笔试题
  • Day 21
  • 智慧农场数字港系统设计与实现
  • fastDDS-gen编译
  • 生成订单幂等性(防止订单重复提交)
  • 职场上,不想受气,就要气场强大,以下三招见效
  • Java哈希算法
  • 【RTOS面试题】ISR中可以使用互斥锁和信号量吗?
  • 21. 合并两个有序链表(递归)
  • 代码随想录算法训练营Day22 | Leetcode 77 组合 Leetcode 216 组合总和Ⅲ Leetcode17 电话号码的字母组合
  • 基于内地城市生活垃圾收运场景的路线规划算法
  • 服务器 Linux 的网络信息
  • 【网络安全】探索AI 聊天机器人工作流程实现RCE
  • Unity补完计划 之 SpriteEditer SingleMode
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • java2019面试题北京
  • web标准化(下)
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 规范化安全开发 KOA 手脚架
  • 将回调地狱按在地上摩擦的Promise
  • 聚类分析——Kmeans
  • 前端js -- this指向总结。
  • 实现菜单下拉伸展折叠效果demo
  • 使用parted解决大于2T的磁盘分区
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • MPAndroidChart 教程:Y轴 YAxis
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • #Linux(权限管理)
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #pragma预处理命令
  • #Z2294. 打印树的直径
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (04)odoo视图操作
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (2.2w字)前端单元测试之Jest详解篇
  • (7)摄像机和云台
  • (aiohttp-asyncio-FFmpeg-Docker-SRS)实现异步摄像头转码服务器
  • (C++二叉树05) 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树
  • (补充)IDEA项目结构
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (论文阅读11/100)Fast R-CNN
  • (七)Java对象在Hibernate持久化层的状态
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (最新)华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—(共12套)(每套四十题)
  • .Net 6.0--通用帮助类--FileHelper
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NetCore+vue3上传图片 Multipart body length limit 16384 exceeded.
  • .NET分布式缓存Memcached从入门到实战
  • .vimrc 配置项
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @EnableWebSecurity 注解的用途及适用场景