undefined

单服务器高性能模式:PPC和TPC

架构设计决定了系统性能的上限,代码实现细节决定了系统性能的下限

单服务器高性能的关键之一就是服务器采取的并发模型,并发模型有如下两个关键设计点:

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

这两个设计点最终都和操作系统的 I/O 模型以及进行模型相关

  • I/O 模型:阻塞、非阻塞、同步、异步
  • 进程模型:单进程、多进程、多线程

一、PPC

PPC 是 Process Per Connection 的缩写,其含义是指每次有新的连接就新建一个进程去专门处理这个连接的请求。基本的流程为:

  1. 父进程接受连接
  2. 父进程 fork 子进程
  3. 子进程处理连接的读写请求
  4. 子进程关闭连接

对于现代的互联网,这种模式的缺点很明显

  • fork 代码高,创建一个进程需要分配很多内核资源,需要将内存映像从父进程复制到子进程,即使现代的操作系统用 Copy on write(写时复制)计数,总体来说创建进程的代码非常高
  • 父子进程通信复杂,需要采用 IPC(Interprocess Communication)之类的进程通信方案。比如:子进程需要在 close 之前告诉父进程自己处理了多少请求以支撑父进程进行全局的统计
  • 支持的并发连接数量有限,如果每个连接存活时间较长,而且新的连接不断进来,则进程数量增多,操作系统调度和切换的频率越来越高,系统压力增大。一般情况下,PPC 方案的并发连接数量最大也就几百

更好一点的方案:

系统在启动的时候就预先创建好进程,然后才开始接受用户的请求,当有新连接进来,就可以省去 fork 进程的操作。当父进程 listen 完之后,去 fork 多个子进程,这些子进程去 accept 同一个 socket,这里有一个“惊群”现象,就是虽然只有一个子进程能 accept 成功,但是阻塞在 accept 上的子进程都会被唤醒,这样就导致了不必要的调度和上下文切换。但是 linux 2.6 以上版本内核已经解决了 accept 惊群问题了。

二、TPC

TPC 是 Thread Per Connection 的缩写,其含义是指每次有新的连接就新建一个线程去专门处理这个连接的请求。线程比进程更轻量化;多线程是共享进程内存空间的,线程间通信也比较简单。

TPC 虽然解决了 fork 代价高和进程间通信复杂的问题,但是也引入了新的问题,具体如:

  • 创建线程依然有代码,高并发(每秒上万连接)还是有性能问题
  • 线程间互斥和共享引入了复杂度,可能会导致死锁
  • 多线程之间互相影响,某个线程出现异常,可能导致整个进程退出(内存越界)

更好一点的方案:提前创建线程