【网络编程】服务器程序框架

文章详细介绍了服务器的基本框架,包括单个服务器和服务器集群的结构。接着,重点讨论了两种高效的事件处理模式——Reactor模式(同步I/O实现)和Proactor模式(异步I/O实现),以及如何使用同步I/O模拟Proactor模式。此外,还探讨了两种并发模式:半同步/半异步模式和领导者/追随者模式,分析了各自的优缺点和适用场景。
摘要由CSDN通过智能技术生成


1、服务器基本框架

在这里插入图片描述
  这张图既可以用来描述一台服务器的基本框架,也可以用来描述一个服务器集群的基本框架,下面这张表说明了在两种情况下各个模块的功能

模块单个服务器服务器集群
I/O处理单元处理客户连接,读写网络数据作为接入服务器,实现负载均衡
逻辑模块业务进程或线程逻辑服务器
网络存储单元本地数据库,文件或缓存数据库服务器
请求队列各单元之间的通信方式各服务器之间的永久TCP连接

2、两种高效的事件处理模式

2.1、Reactor模式(由同步I/O模型实现)

  该模式下,主线程只负责监听文件描述符上是否有事件发生,所有的工作都在工作线程上完成。

  使用同步I/O模型(epoll_wait)实现的Reactor模式工作流程为:

  • 主线程往epoll内核事件表中注册socket上的读就绪事件。
  • 主线程调用epoll_wait等待socket上有数据可读。
  • socket上有数据可读时,epoll_wait通知主线程,主线程将socket可读事件放入请求队列。
  • 睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件。
  • 主线程调用epoll_wait等待socket可写。
  • socket可写时,epoll_wait通知主线程,主线程将socket可写事件放入请求队列。
  • 睡眠在请求队列上的某个工作线程被唤醒,它往socket上写入服务器处理客户请求的结果。

  工作线程从请求队列中取出事件后,如果是读事件,执行读数据和处理请求的操作,如果是写事件,执行写数据的操作。所以,在Reactor模式中,没有必要区分读工作线程以及写工作线程
在这里插入图片描述

2.2、Proactor模式(由异步I/O模型实现)

  在该模式下,Proactor模式将所有的I/O操作交给主线程和内核来处理,工作线程仅仅负责业务逻辑。
  使用异步I/O模型(以aio_readaio_write为例)实现的Proactor模式的工作流程如下:

  • 主线程调用aio_read函数向内核注册socket上的读完成事件,并告诉内核用户读缓冲区的位置,以及读操作完成时要如何通知应用程序。
  • 主线程继续处理其他逻辑
  • socket上的数据被读入用户缓冲区之后,内核将向应用程序发送一个信号,通知应用程序数据已经可用
  • 应用程序预先定义好的信号处理函数选择一个工作线程来处理客户请求。工作线程处理完客户请求之后,调用aio_write函数向内核注册socket上的写完成事件,并告诉内核用户写缓冲区的位置,以及写操作完成时如何通知应用程序
  • 主程序继续处理其他逻辑。
  • 当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,以通知应用程序数据以及发送完毕。
  • 应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭socket

  由于在这种模式下,连接socket上的读写事件是通过aio_read/aio_write向内核注册的,因此内核用过信号来向应用程序报告连接socket上的读写事件。所以,这种模式下的主线程epoll_wait调用仅仅用来检测监听socket上的连接请求事件,而不能检测socket上的读写事件。
在这里插入图片描述

2.3、模拟Proactor模式(由同步I/O模型模拟实现)

  使用同步I/O模型(以epoll_wait为例)模拟出的Proactor模式的工作流程如下:

  • 主线程往epoll内核事件表中注册socket上的读就绪事件。
  • 主线程调用epoll_wait等待socket上有数据可读
  • 当socket上有数据可读时,epoll_wait通知主线程。主线程从socket循环读取数据,直到没有更多数据可读,然后将读取到的数据封装成一个请求对象并插入请求队列。
  • 睡眠在请求队列上的某个工作线程被唤醒,他获取请求对象并处理客户请求,然后往epoll内核时间表中注册socket上的写就绪事件。
  • 主线程调用epoll_wait等待socket可写
  • socket可写时,epoll_wait通知主线程,主线程往socket上写入服务器处理客户端请求的结果。

在这里插入图片描述

3、两种高效的并发模式

  并发模式是指I/O处理单元和多个逻辑单元之间协调完成任务的方法。这里主要介绍两种并发编程模式:半同步/半异步模式和领导者/追随者模式。

3.1、半同步/半异步模式

  这里的同步异步与I/O模型中的同步异步不同。

  • I/O模型中,同步和异步区分的是内核向应用程序通知的是哪种I/O事件(是就绪事件还是完成事件),以及由谁来完成I/O读写(是应用程序还是内核)。
  • 并发模型中,同步指的是程序完全按照代码序列顺序执行,异步指的是程序的执行需要由系统事件来驱动。

  按照同步方式运行的线程称为同步线程,逻辑简单但运行效率低,实时性差。按照异步方式运行的线程称为异步线程,效率高实时性强,但是程序复杂难以调试,是很多嵌入式程序采用的模型。所以,对于服务器这样的既要求实时性有要求可以同时处理多个客户请求的应用程序,我们就应该同时使用同步线程以及异步线程来实现。
  结合考虑两种事件处理模式以及几种I/O模型,则半同步/半异步模式存在许多变体,其中包括半同步/半反应堆模式。这种模式采用的事件处理模式是Reactor模式。

在这里插入图片描述
  这种模式的缺点在于:

  • 主线程和工作线程共享请求队列。主线程往请求队列中添加任务,或者工作线程从请求队列中取出任务,都需要对请求队列加锁保护,从而浪费CPU时间。
  • 每个工作线程在同一时间只能处理一个客户请求。如果客户数量较多,而工作进程较少,那么请求队列中就会堆积任务对象,客户端的响应速度就会降低。如果通过添加工作进程来解决这一问题的话,则会导致工作进程切换导致的时间增加。

  除此之外,可以通过将请求队列换成工作线程与主线程之间连接的管道,这样会使得这种半同步/半异步方式更加高效。

3.2、领导者/追随者模式

  领导者/追随者模式是多个工作线程轮流获得事件源集合、轮流监听、分发并处理事件的一种模式。在任意时间点,程序都仅有一名领导者,他负责监听I/O事件,而其他线程都是追随者,他们休眠在进程池中等待成为新的领导者。此时,如果领导者检测到了I/O事件,那么它就会现在进程池中推选出新的领导者,然后去处理I/O事件。此时,新的领导者等到I/O事件,旧的领导者处理I/O事件,二者就实现了并发。
  由于领导者线程自己监听了I/O事件并处理客户请求,因而领导者/追随者模式不需要再线程之间传递任何额外的数据,也无需向半同步/半反应堆模式那样在线程之间同步对请求队列的访问。但领导者/追随者的一个明显的缺点是仅支持一个事件源集合,因而无法让每个工作线程独立的管理多个连接。


《Linux高性能服务器编程》学习笔记

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rockict_z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值