一、引言
网络I/O是每名程序员必须掌握的一项内容,尤其是在通信的过程中,不论是客户端到服务器,还是服务器集群间通信、服务器内部数据交互,都少不了网络I/O操作。网络I/O的性能是影响系统整体性能的一项关键因素,本文将对四种I/O模型的概念进行介绍,并详述各模型的优势与劣势。
二、概念介绍
在介绍网络模型之前先简单引入几个概念:
同步:“同步”并不像字面意思–两个操作同时进行,恰好相反,“同步”的意思是两个操作步骤有先后顺序,一个操作依赖另一个操作的结果。
异步:两个操作之间,后操作不需要依赖前一操作的结果。最终操作的结果可通过通知、回调等形式通知调用者。
阻塞:调用函数暂无结果时需将线程挂起。
非阻塞:等待调用函数结果时,该调用者不会阻塞当前线程。
在以上四个概念的基础之上进行两两组合便得到了四种I/O模型:同步阻塞(BIO)、同步非阻塞(NIO,和Java里提到NIO概念有所区别),异步阻塞和异步非阻塞(AIO)。
三、编程模型
针对上述网络I/O模型,可抽象出如下网络编程模型:
PPC( Process Per Connection )模型和Prefork模型:PPC模型的核心理念是为每一个连接分配一个进程。Prefork模型则考虑到PPC模型在fork进程时比较耗费性能,于是提前预留了一些进程(个人理解类似于线程池的理念),Prefork模型也是Apache三种MPM模型之一。PPC和Prefork模型的优点是编程较为简单,但缺点也十分明显,即:性能开销较大,进程间通信(IPC,InterProcess Communication)复杂,且支持的连接数不高(量级仅为102)。
图1:经典的PPC模型
TPC模型(Thread per connnection)和Prethread模型:TPC模型相较于PPC模型就是用一个线程来处理一个连接,Prethread模型则是预留了线程。相对于进程,线程创建的开销较小,但线程之间变量共享复杂,线程可能存在异常退出的情况,频繁的上下文切换也是此种网络模型的瓶颈。
Reactor模型:Reactor模型是一种基于IO多路复用的事件响应网络编程模型,诸如Java里的selector以及linux里的epoll。
图2:单reactor单线程模型
Reactor模型将连接事件交由Acceptor处理,如果是读写事件则交由Handler处理。由于Reactor采取的是事件响应机制,相对于PPC或者TPC模型阻塞的不是进程(线程),而是Reactor对象,因此具有更好的性能,大名鼎鼎的redis就是采用了单reactor 单线程模型。由于单reactor单线程模型无法发挥多核CPU的优势,因此后续衍生出了单reactor多线程、多reactor多进程/线程,此类的实现有Memcached、Nginx、Netty等。
Proactor模型:核心内容是向内核注册Proactor和handler,由内核完成IO操作,IO操作完成后再由Handler进行业务逻辑处理。
图3:Proactor模型
Windows环境下IOCP实现了Reactor模型,但linux操作系统中目前对Reactor的支持并不成熟,理论上Proactor模型比Reactor模型性能更高,但经相关人士评测,两者性能差别并不是很大,大约为10%左右。
四、总结
IO作为网络编程及服务端编程必要的知识领域,其重要性不言而喻。在诸多网络模型中综合评估,多Reactor 多线程的网络编程模型是目前较为完美的技术方案,且已有诸多开源实现(如Netty、memcached使用的libevent以及node.js使用的libuv),此文章希望能为同学们在以后的工作中面对高性能网络编程时提供一定的帮助。
作者:任爱华、张宏源
参考链接:
https://httpd.apache.org/docs/2.4/mod/mpm_common.html
https://time.geekbang.org/column/article/8805
往期回顾
云计算时代-选择适合业务的云负载均衡
终端防泄密功能与原理解析
由浅入深探索基于深度学习的词向量构建
搞砸SaaS开发?你要知道这些事!
原创文章,作者:EBCloud,如若转载,请注明出处:https://www.sudun.com/ask/32742.html