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

总结《Linux高性能服务器编程》第八章

第八章 高性能服务器程序框架

服务器模型

  • C/S(客户端/服务器)模型
    • 实现简单,适合资源相对集中的场合;
    • 缺点:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应;

  • P2P(Peer to Peer,点对点)模型
    • 网络上所有主机地位对等,典型范例如云计算机群;

    • 缺点:主机之间很难互相发现,所以实际使用的P2P模型通常带有一个专门的发现服务器;
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ik6dvw80-1668427663773)(img/Linux高性能服务器编程/image-20221026193306268.png)]

    • 从编程角度讲,P2P模型可以看作C/S模型的扩展,每台主机既是客户端,又是服务器

服务器编程框架

在这里插入图片描述

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

I/O模型

  • socket在创建的时候默认是阻塞的,socket的基础API中,可能被阻塞的系统调用包括acceptsendrecvconnect
  • 阻塞的文件描述符为阻塞I/O,称非阻塞的文件描述符为非阻塞I/O
    • 针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止;
    • 针对非阻塞I/O执行的系统调用则总是立即返回,而不管事件是否已经发生,如果事件没有立即发生,这些系统调用就返回-1,并区分原因;
  • 非阻塞I/O通常要和其他I/O通知机制一起使用:
    • 同步I/O模型:I/O的读写操作在I/O事件发生之后
      • I/O复用:程序阻塞于I/O复用系统调用,但可同时监听多个I/O事件,对I/O本身的读写操作是非阻塞的;
      • SIGIO信号:信号触发读写就绪事件,用户程序执行读写操作,程序没有阻塞阶段;
    • 异步I/O模型:读写操作总是立即返回,不论I/O是否阻塞,真正的读写操作由内核接管
    • “同步”和“异步”区分的是内核向应用程序通知的是何种I/O事件(是就绪事件还是完成事件);

同步异步阻塞非阻塞这些概念,是从不同的层次看待问题的

  1. 阻塞和非阻塞是指函数内部遇到资源繁忙时,线程是否挂起;

  2. 同步和异步是指函数返回之时, 能不能保证任务完成;

    a. 异步只有非阻塞,只有同步才区分阻塞和非阻塞;

    b. 同步是在更大的任务层面整体看待的,而不是函数内部的细节

两种高效的事件处理模式

  • 服务器程序通常需要处理三类事件:I/O事件、信号及定时事件;

  • 同步I/O模型通常用于实现Reactor模式异步I/O模型则用于实现Proactor模式

  • 主线程指I/O处理单元,工作线程指逻辑单元;

  • Reactor模式
    • 要求主线程只负责监听文件描述上是否有事件发生,有的话就立即将该事件通知工作线程;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-13D7VOBQ-1668427663774)(img/Linux高性能服务器编程/image-20221026200446175.png)]

  • Proactor模式
    • 将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑;

    **[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kIezmibF-1668427663774)(img/Linux高性能服务器编程/image-20221026200802165.png)]**

两种高效的并发模式

  • 如果程序是计算密集型,并发编程并没有优势,反而由于任务的切换使效率降低;

  • 如果程序是I/O密集型,让程序阻塞于I/O操作将浪费大量的CPU时间,因此当前被I/O操作所阻塞的执行线程可主动放弃CPU,并将执行权转移到其他线程;

  • 并发编程主要有多进程和多线程两种方式;

  • 服务器主要有两种并发编程模式:半同步/半异步(half-sync/half-async)模式和领导者/追随者(Leader/Followers)模式;

  • 半同步/半异步模式
    • 在并发模式中,“同步”指的是程序完全按照代码序列的顺序执行,“异步”指的是程序的执行需要由系统事件(中断、信号等)来驱动;

      • 同步线程的效率低,实时性差,但逻辑简单;
      • 异步线程的执行效率高,实时性强,但程序复杂;
    • 半同步/半异步模式中,同步线程用于处理客户逻辑,异步线程用于处理I/O事件;

    • 半同步/半反应堆(half-sync/half-reactive)模式

      • 主线程插入请求队列中的任务是就绪的连接socket,说明事件处理模式是Reactor模
        式;
      • 缺点:主线程和工作线程共享请求队列,需要加锁保护;每个工作线程在同一时间只能处理一个客户请求,如果客户数量多,而工作线程少,则请求队列中将堆积很多任务对象;
    • 相对高效的半同步/半异步模式

      • 主线程只管理监听socket,连接socket由工作线程来管理;
      • 主线程通过管道向工作线程派发socket;
      • 每个线程(主线程和工作线程)都维持自己的事件循环,每个线程都工作在异步模式,所以它并非严格意义上的半同步/半异步模式;
  • 领导者/追随者模式
    • 多个工作线程轮流获得事件源集合,轮流监听、分发并处理事件;
    • 在任意时间点,程序都仅有一个领导者线程负责监听I/O事件,其他线程则都是追随者,它们休眠在线程池中等待成为新的领导者;
    • 当前的领导者如果检测到I/O事件,首先要从线程池中推选出新的领导者线程,然后处理I/O事件,新的领导者等待新的I/O事件,而原来的领导者则处理I/O事件,二者实现了并发
    • 领导者/追随者模式包含如下几个组件:句柄集、线程集、事件处理器和具体事件处理器

有限状态机

  • 逻辑单元内部的一种高效编程方法;

提高服务器性能的其他建议

  • 池:以空间换时间
    • 池是一组资源的集合,在服务器启动之初就被完全创建好并初始化(这静态资源分配),当服务器开始处理客户请求时,需要相关的资源可以直接从池中获取,无须动态分配
    • 根据不同的资源类型,池分为多种
      • **内存池:**用于socket的接收缓存和发送缓存;
      • **进程池和线程池:**常用于并发编程,当我们需要一个工作进程或线程来处理请求时,可以直接从进程或线程池中取得一个执行实体;
      • 连接池服务器预先和数据库程序建立的一组连接的集合;
  • 数据复制
    • 高性能服务器应该避免不必要的数据复制
      • 用户代码和内核之间发生数据复制;
      • 用户代码内部(不访问内核)的数据复制:考虑使用共享内存,而不是使用管道或者消息队列;
  • 上下文切换和锁
    • 并发程序必须考虑上下文切换的问题,即进程切换或线程切换导致的的系统开销;
      • 即使是I/O密集型的服务器,也不应该使用过多的工作线程,否则线程间的切换将占用大量的CPU时间;
    • 并发程序需要考虑的另外一个问题是共享资源的加锁保护
      • 应该尽量避免使用锁,若必须要使用,则可以考虑减小锁的粒度;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值