传统网络模型
PPC和prefork
优点
实现简单
缺点
- PPC:fork代价高,性能低
- 父子进程通信要用IPC,监控统计等实现会比较复杂
- OS的上下文切换会限制并发连接数,一般几百
案例
- 世界上第一个Web服务器CERN httpd采用PPC模式
- Apache MPM prefork模式,默认256个连接
TPC和prethread
优点
- 实现简单
- 无需IPC,线程间通信即可
- 无需fork,线程创建代价低
缺点
- 线程互斥和共享比PPC/prefork要复杂
- 某个线程故障可能导致整个进程退出
- OS的上下文切换会限制并发连接数,一般几百,但比PPC/prefork要多
案例
Apache 服务器 MPM worker 模式就是 prethread模式的变种(多进程 + prethread),默认支持16 × 25= 400 个并发处理线程
Reactor网络模型
Reactor:基于多路复用的事件响应网络编程模型
多路复用
多个连接复用同一个阻塞对象,例如Java的Selector、epoll的epoll_fd(epoll_create函数创建)
事件响应
不同的事件分发给不同的对象处理,Java的事件有OP_ACCEPT、OP_CONNECT、OP_READ、OP_WRITE
优缺点
- 实现比传统网络模型要复杂
- 支持海量连接
Reactor模式
模式1-单 Reactor 单进程/单线程
- Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行分发
- 如果是连接建立的事件,则由 Acceptor 处理,Acceptor 通过 accept 接受连接,并创建一个 Handler 来处理连接后续的各种事件
- 如果不是连接建立事件,则 Reactor 会调用连接对应的 Handler(第2步中创建的 Handler)来进行响应。Handler 会完成 read → 业务处理 → send 的完整业务流程
优点
- 实现简单,无进程通信,无线程互斥和通信
- 无上下文切换,某些场景下性能可以做到很高
缺点
- 只有一个进程,无法发挥多核CPU的性能;只能采取部署多个系统来利用多核CPU,但这样会带来运维复杂度
- Handler在处理某个连接上的业务时,整个进程无法处理其他连接的事件,可能导致性能瓶颈
案例
Redis
模式2-单 Reactor 多线程
- 主线程中,Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行分发
- 如果是连接建立的事件,则由 Acceptor 处理,Acceptor 通过 accept 接受连接,并创建一个 Handler 来处理连接后续的各种事件
- 如果不是连接建立事件,则 Reactor 会调用连接对应的 Handler(第2步中创建的 Handler)来进行响应
- Handler 只负责响应事件,不进行业务处理;Handler 通过 read 读取到数据后,会发给 Processor 进行业务处理
- Processor 会在独立的子线程中完成真正的业务处理,然后将响应结果发给主进程的 Handler 处理;Handler 收到响应后通过 send 将响应结果返回给 client
优点
充分利用了多核CPU的优势,性能高
缺点
- 多线程数据共享和访问比较复杂
- Reactor承担了所有事件的监听和响应,只在主线程中运行,瞬时高并发时会成为性能瓶颈
模式3-多 Reactor 多进程/线程
- 父进程中 mainReactor 对象通过 select 监控连接建立事件,收到事件后通过 Acceptor 接收,将新的连接分配给某个子进程
- 子进程的 subReactor 将 mainReactor 分配的连接加入连接队列进行监听,并创建一个 Handler 用于处理连接的各种事件
- 当有新的事件发生时,subReactor 会调用连接对应的 Handler(即第2步中创建的 Handler)来进行响应
- Handler 完成 read → 业务处理 → send 的完整业务流程
优点
- 充分利用了多核CPU的优势,性能高
- 实现简单,父子进程(线程)交互简单,subReactor子进程(线程)间无互斥共享或通信
缺点
没有明显的缺点,虽然自己实现会很复杂,但是目前已经有非常成熟的开源方案
案例
Memcached、Netty、Nginx等
注意:实现细节都有一些差异,例如Memcached用了事件队列、Nginx是子进程accept
Proactor网络模型
- Proactor Initiator 负责创建 Proactor 和 Handler,并将Proactor和 Handler 都通过 Asynchronous Operation Processor 注册到内核
- Asynchronous Operation Processor 负责处理注册请求,并完成I/O 操作
- Asynchronous Operation Processor 完成 I/O 操作后通知Proactor
- Proactor 根据不同的事件类型回调不同的 Handler 进行业务处理
- Handler 完成业务处理,Handler 也可以注册新的Handler 到内核进程
优点
理论上性能要比Reactor更高一些,但实测性能差异不大,大约10%以内
缺点
- 操作系统实现复杂,Linux目前对Proactor模式支持并不成熟
- 程序调试复杂
案例
Windows IOCP
网络模型对比
复杂度 | 连接数量 | 应用场景 | |
---|---|---|---|
PPC | 低 | 常量连接,几百 | 内部系统、中间件 |
prefork | 低 | 常量连接,几百 | 内部系统、中间件 |
TPC | 低 | 常量连接,几百 | 内部系统、中间件 |
prethread | 低 | 常量连接,几百 | 内部系统、中间件 |
Reactor | 中,程序复杂 | 海量连接,上万 | 互联网、物联网、中间件 |
Proactor | 高,OS内核复杂 | 海量连接,上万 | 互联网、物联网、中间件 |
三种网络模型实战技巧
“多Reactor多线程”是目前已有技术中接近完美的技术方案:
- 所有场景
- 所有平台
- 性能和Proactor接近
直接用开源框架,千万不要自己去实现,例如Netty、libevent(Memcached网络框架)、libuv(node.js底层网络框架)