基于主从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,增加传输效率的同时可以增加安全性。也可以优化日志系统和监控服务器工具,后期问题也可以更好的进行维护。 

  • 11
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
主从 Reactor 多线程是一种常见的网络编程模型,它通常用于高并发服务器的开发。该模型的核心思想是将网络 I/O 与业务逻辑分离,并通过多线程来实现并发处理。 在主从 Reactor 多线程模型中,主线程(也称为 Acceptor 线程)负责监听客户端连接请求,并将连接分配给工作线程(也称为 EventLoop 线程)进行处理。工作线程负责处理连接上的读写事件和业务逻辑,并将需要执行的任务交给线程池中的线程进行处理。 主从 Reactor 多线程模型主要包含以下组件: 1. Acceptor:负责监听客户端连接请求,并将连接分配给工作线程进行处理。 2. EventLoop:负责处理连接上的读写事件和业务逻辑,并将需要执行的任务交给线程池中的线程进行处理。 3. Thread Pool:用于执行异步任务,例如数据库查询和计算密集型任务等。 在实现主从 Reactor 多线程模型时,需要注意以下几点: 1. Acceptor 线程与工作线程之间应该使用线程安全的队列进行通信。 2. 每个工作线程应该拥有一个 EventLoop 对象,用于处理连接上的读写事件和业务逻辑。 3. 线程池中的线程应该使用异步方式执行任务,以避免阻塞工作线程。 总之,主从 Reactor 多线程模型是一种高效的网络编程模型,可以有效地提高服务器的并发处理能力。但是它的实现比较复杂,需要考虑线程同步、线程安全和性能等方面的问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值