文章目录
- 网络演变过程
- 1、阻塞IO(BIO)
- 实现
- 缺点
- 2、非阻塞IO(NIO)
- 实现
- 改进后
- 设置非阻塞IO
- 缺点
- 3、IO多路复用第一版(select/poll)
- 问题点
- 改进
- 缺点
- 4、IO多路复用第二版(epoll)
- 5、信号驱动IO
- 区别
- 缺点
- 6、异步IO(AIO)
- 区别
- 小总结
- 经典网络模型
- 1、单Reactor单线程
- 经典实现
- 2、单Reactor线程池
- 3、多Reactor多线程(多进程)
- 4、Proactor
网络演变过程
linux内核演变:
1、阻塞IO(BIO)
实现
- 简单的c/s模型,通常一个client分配一个线程处理(可以使用队列+线程池优化模型)
缺点
并发
数量少(线程有限)线程上下文切换
影响性能(可用线程池缓解)
2、非阻塞IO(NIO)
实现
BIO和NIO的区别在于内核中数据尚未就绪
时:
- 阻塞IO
一直处于阻塞状态
,直到数据就绪并从内核态拷贝到用户态后返回 - 非阻塞IO
直接返回
用户态EWOULDBLOCK
错误
改进后
可以在一个线程中管理多个client
设置非阻塞IO
socket
方法创建时候第二个参数type
设置SOCK_NONBLOCK
fcntl
方法第三个参数设置O_NONBLOCK
缺点
需要不断轮训
询问内核数据是否就绪,涉及到很多无效的系统调用
(system call)
3、IO多路复用第一版(select/poll)
问题点
非阻塞socket不知道什么时候有数据,所以需要主动询问。
改进
- 每个client都要询问 —> 批量询问(系统
调用次数
O(n) —> O(1)) - 从主动询问变成等待通知(系统
调用次数
下降)
缺点
- 每次查询都会把多个client从
用户态拷贝到内核态
。(管理百万级别及以上的时候会带来很大开销) - 处理有响应的client的时候要遍历所有client判断是否有响应。(
模糊通知
)
4、IO多路复用第二版(epoll)
改进:
- 监听fd每次全量维护 —> 监听fd初始化 +
增量维护
- 模糊通知 —>
明确通知
(内部使用就绪列表)
5、信号驱动IO
区别
无需进程主动去check活跃的socket,把检查工作交给内核。
缺点
当有大量IO操作时,信号较多,SIGIO处理函数不能及时处理可能导致信号队列溢出
,而且内核空间与用户空间的频繁信号交互性能也较低
。
6、异步IO(AIO)
区别
epoll
(同步非阻塞IO)封装了一个异步事件的通知机制,不负责IO读写操作
iocp
(异步IO)封装了异步的消息事件的通知机制,同时封装了部分IO操作
iocp
将接收发送等io操作也封装到了内核中,对处理大量短连接比较高效。
linux
也有AIO
,如gcc AIO
、libaio
等。
流程如下:
小总结
经典网络模型
1、单Reactor单线程
定义:单线程主要针对IO操作而言,I/O中的accept
()、read
()、write
()都是在一个线程完成的。
问题:
IO操作和业务逻辑处理操作在一个线程上
,大大降低了I/O请求的处理效率。- 无法充分利用和发挥多核 CPU 的性能。
- 可靠性问题,线程意外终止,或者进入死循环,会导致整个系统通信模块不可用,不能接收和处理外部消息,造成节点故障。
经典实现
redis:
使用单Reactor
单线程,在6.0版本前,核心业务部分使用单线程。官方数据:10万QPS。
6.0版本之后多线程处理网络数据的读写和协议的解析,单线程执行命令。QPS还能提高1~2倍。
为什么用单线程
- 抛开持久化不谈,Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度,因此多线程并不会带来巨大的性能提升。
- 多线程会导致过多的上下文切换,带来不必要的开销。
- 引入多线程会面临线程安全问题
单线程的缺点:顺序执行影响后续事件
2、单Reactor线程池
改进:引入了线程池,用来专门处理业务逻辑操作,提升I/O响应速度
,利用多 CPU 的处理能力。
问题:
- 多线程数据共享和访问比较复杂。
- 管理百万级连接、高并发大数据量时,单个
Reactor
线程仍然会效率比较低下。
3、多Reactor多线程(多进程)
改进:扩展了Reactor
。引入多个Reactor
。也称为主从结构。父线程和子线程的职责明确。
扩展Reactor可以是多线程也可以是多进程。
方式 | 资源分配 | 经典实现 |
---|---|---|
多线程 | 线程之间如果涉及资源竞争的话,需要通过锁来保证同步 | netty、memcached等 |
多进程 | 需要进程间通信 | nginx等 |
4、Proactor
对比Reactor
:
Proactor
在处理高耗时 IO 时的性能要高于Reactor
,但对于低耗时 IO 的执行效率提升并不明显Proactor
的异步性使其并发处理能力要强于Reactor
Proactor
的实现逻辑复杂,编码成本较Reactor
要高很多Proactor
的异步高度依赖于操作系统对于异步的支持。若操作系统对异步的支持不好,Proactor
的性能还不如Reactor
Reactor
是同步非阻塞网络模型,Proactor
是异步非阻塞网络模型
问题:Linux 对 AIO支持的不太友好