知识卡片
PPC与prefork:每连接一进程模型的三大瓶颈
内容
PPC(Process Per Connection)是每来一个新连接就fork一个新进程专门处理这个连接的传统UNIX网络服务器模型:父进程accept连接后fork出子进程,子进程负责这个连接的读写和业务处理,处理完后子进程close连接(父进程fork后立刻调用的close只是把连接文件描述符的引用计数减一,真正关闭要等子进程也close、引用计数归零才发生)。这个模型实现简单,在连接数不多的场景(如数据库服务器)或互联网兴起前的普通业务场景下运作良好,世界上第一个web服务器CERN httpd用的就是这套模型,但随着互联网并发量从几十暴涨到成千上万,它的三个瓶颈就凸显出来了:一是fork代价高——创建一个进程需要操作系统分配大量内核资源、把父进程的内存映像复制给子进程,即使有Copy on Write优化,总体代价依然很大;二是父子进程通信复杂——fork时文件描述符能通过内存映像复制传给子进程,但fork完成后父子进程之间要交换信息(比如子进程要把自己处理了多少请求汇报给父进程做全局统计)就必须借助IPC这类进程间通信机制,实现起来比较麻烦;三是支持的并发连接数量有限——如果连接存活时间长且新连接源源不断,进程数会持续膨胀,操作系统进程调度和切换的开销也随之上升,PPC方案通常最多也就能撑住几百并发连接。prefork是为了解决”fork代价高导致用户首次访问变慢”这个问题而生的变体:系统启动时就提前把进程创建好,等真正有连接进来时就省去了现场fork的开销;实现的关键是让多个子进程都去accept同一个socket,操作系统保证最终只有一个进程能accept成功,但这会带来”惊群”现象——虽然只有一个子进程真正accept成功,所有阻塞在accept上的子进程却都会被唤醒,造成不必要的进程调度和上下文切换(好在Linux 2.6内核之后这个问题已经被操作系统层面解决)。prefork虽然省去了现场fork的延迟,但父子进程通信复杂、并发连接数有限这两个PPC固有的瓶颈依然没有解决,因此实际应用不算多,Apache的MPM prefork模式默认最大只支持256个并发连接,通常只在需要高可靠性或兼容旧软件的场景下才被推荐使用。
结构图:
flowchart TB
A["PPC:每连接一进程"]
A --> B["瓶颈①fork代价高<br/>需分配内核资源+复制内存映像"]
A --> C["瓶颈②父子进程通信复杂<br/>需借助IPC机制"]
A --> D["瓶颈③并发连接数有限<br/>进程调度切换开销随连接数飙升,通常上限几百"]
A --> E["prefork变体:提前预创建进程<br/>省去现场fork延迟"]
E --> F["解决了:首次访问慢的问题"]
E --> G["新增:惊群现象<br/>多子进程accept同一socket,唤醒代价<br/>(Linux 2.6+内核层已解决)"]
E --> H["未解决:父子进程通信复杂+连接数有限<br/>实际应用不多,Apache MPM prefork默认256并发上限"]