《从 0 开始学架构》学习归整(七)单服务器高性能模式:PPC、TPC、Reactor 和 Proactor

内容纲要

架构设计是高性能的基础。架构设计决定了性能的上限,实现细节决定性能的下限。

提升性能的方式

提升单台服务器性能

单服务器的高性能关键之一就是服务采取的并发模型。并发模型的关键设计点:

  • 服务器如何管理连接
  • 服务器如何处理请求

以上两点都和操作系统的 I/O 模型(阻塞、非阻塞、同步、异步)和进程模型(单进程、多进程、多线程)有关。

单服务器高性能模式

PPC(Process Per Conenction)

即每个新连接进来,就创建一个进程去专门处理这个连接。

PPC

  • 父进程接收(accept)连接
  • 父进程(fork)子进程
  • 子进程读(read)写(write)数据和处理业务
  • 子进程关闭(close)连接

父进程的 close 是让连接的文件描述符引用计数减一,并非关闭连接;真正的关闭连接由子进程完成。

PPC 模式的优点
  • 实现简单
PPC 模式的缺点
  • fork 代价高
    • prefork(流程见下图):即提前 fork 进程,子进程共同 accept 一个 socket,可以减少连接过程中的进程创建时间
      • 子进程共同监听一个 socket,容易导致惊群现象出现
  • 父子进程通信复杂
  • 支持并发连接数有限(进程过多,系统负担太重)

prefork

TPC(Thread Per Connection)

即每个新连接进来,就创建一个线程专门去处理这个连接。

TPC

  • 父进程接收(accept)连接
  • 父进程创建子线程(pthread)
  • 子线程读(read)写(write)数据和处理业务
  • 子线程关闭(close)连接
TPC 的优点
  • 创建线程资源消耗小(相比进程;消耗小,但依然是有消耗的)
    • prethread:与 prefork 类似,但不存在“惊群现象”
  • 线程间通信简单
  • 主进程不需要 close socket 操作
TPC 的缺点
  • 线程间互斥、共享等问题较复杂,设计不当容易出现死锁等问题
  • 线程间可能互相影响(异常未处理好,可能导致整体崩溃)

Reactor

即每个连接进来,通过 I/O 多路复用技术,把连接交给相应的业务代码进行处理(即 I/O 多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程)。Reactor 模式也叫 Dispatcher 模式。

核心组成:

  • Reactor:负责监听、分配事件
  • 处理资源池(进程池、线程池):负责处理事件

典型方案:

  • 单 Reactor;单进程/线程
    • 过程
      • Reactor 对象通过 select 监控连接事件
      • 收到事件后通过 Dispatch 分发
        • 如果是建立连接事件,由 Acceptor 通过 accept 接受连接,并创建 Handle 处理后续业务
        • 如果不是建立连接事件,Reactor 调用之前创建的对应 Handle 处理相关事件
      • Handle 完成 read -> 业务处理 -> send 业务流程
    • 优点
      • 简单
      • 无进程间通信、竞争
    • 缺点
      • 无法发挥多核性能(多部署增加系统复杂度)
      • Handle 在除了业务时,进程无法处理其他连接事件
    • 适用场景:业务处理非常快的场景(如:Redis)

图片标题

  • 单 Reactor;多线程
    • 过程
      • 主线程 Reactor 通过 select 监控事件
      • 收到事件后通过 Dispatch 分发
        • 如果是建立连接事件,由 Acceptor 通过 accept 接收连接,并建立一个 Handle 处理后续业务
        • 如果不是建立连接事件,则调用之前创建的对应 Handle 来处理后续业务
      • Handle 负责响应事件,不处理具体业务;通过 read 读取到数据后发给 Processor 处理
      • Processor 在独立子线程中处理业务;处理完后将响应结果发给主 Handle 处理
      • 主 Handle 通过 send 将结果返回给 client
    • 优点
      • 可以发挥多核性能
    • 缺点
      • 多线程数据共享、访问复杂
      • Reactor 承担所有事件监听和响应,压力大

图片标题

  • 单 Reactor;多进程/线程
    • 过程
      • 父进程中 mainReactor 通过 select 监控连接建立事件
      • 收到后通过 Acceptor 将新的连接分配给某个子进程
        • 子进程通过 subReactor 将 mainReactor 分配的连接加入监听队列,并创建 Handle 用于处理各种事件
        • 当有事件发生时,subReactor 调用之前创建的对应 Handle 进行处理
        • Handle 完成 read->业务处理->send 的业务流程
    • 优点
      • 简单
        • 父子进程分工明确:父进程监听连接,子进程完成后续业务
        • 父子进程交互简单:只有父进程将连接交给子进程,子进程不需要跟父进程交互
        • 子进程之间互不干扰(除非业务有交集)

图片标题

Proactor(稍微了解就可以,应用环境不是很好)

Reactor 是非阻塞同步网络模型(read 和 send 都需要用户进程同步操作);把 read 和 send(I/O)改为异步,即 Proactor。

方案:

  • 过程
    • Proactor Initiator 负责创建 Proactor 和 Handle,并通过 Asynchronous Operation Processor(以下简称 AOP) 将 Proactor 和 Handle 都注册到内核
    • AOP 负责处理注册请求,并完成 I/O 操作
    • 完成操作后通知 Proactor
    • Proactor 根据不同事件类型回调不同的 Handle 进行业务处理
    • Handle 完成业务处理,也可以注册新的 Handle 到内核

Proactor 理论上效率比 Reactor 高,但要实现真正异步 I/O 操作系统需要完成大量工作。目前 Windows 通过 IOCP 实现真正异步 I/O;Linux 的 AIO 尚不完善,因此 Linux 下,基本还是使用 Reactor 为主。

图片标题

并发模式的选择

不同并发模式的选择需要考虑的因素有:

  • 响应时间(RT)
  • 并发数(Concurrency)
  • 吞吐量(TPS)

吞吐量 = 并发数 / 平均响应时间

不同的系统对不同指标的需求也不一样。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注