主流 I/O 模型
阻塞IO、非阻塞IO、异步 IO 。
BIO 模型
同步阻塞 模型,一个客户单对应一个链接的处理线程
缺点:
1、IO 中如果进行 read 是阻塞操作,如果请求的链接操作不做任何操作,也会导致线程阻塞,浪费线程资源
2、如果线程很多,会导致服务器压力增加,比如 C10K问题
引用场景:
BIO 方式运用数目比较小且固定的架构,这种方式对服务器资源要求比较高,但是程序简单容易理解。
NIO 模型
同步非阻塞,是服务器实现的模式是一个线程可以处理多个请求(链接),客户端发送的链接都会注册到多路复用器 selector 上,多路复用器轮训到介入的所有 IO 请求进行处理。
应用场景:
NIO方式适用于链接数目多(轻操作) 的架构,比如聊天服务器,弹幕系统,服务器间通讯,编程比较复杂。Java NIO 模型如下图所示:
总结:
NIO 的三大核心组件:Channel(通道)、Buffer (缓冲区)、Selector (多路复用器)
1、Channel 类似流,每个 Channel 对应一个 buffer 缓冲区。
2、Channel 组册到 Selector 上,由 Selecotor 根据 Channel 读写事件发生时交给空闲线程处理。
3、NIO 中 Buffer 与 Channel 都是可读可写的。
NIO 模型实现
在 linux 系统中是通过调用系统内核函数来创建 socket ,selecotor 对应操作系统的 epoll 描述符。可以将 socket 的连接文件描述符绑定到 epoll 文件描述符上,进行事件的异步通知,实现一个线程处理,并且减少大量的无效遍历,事件处理交给了操作系统的内核,提升效率。
Redis 线程模型
Redis 是一个典型的基于 epoll 的 nio 线程模型, epoll 实例手机所有的事件(连接与读事件)由一个服务线程处理所有命令。
Redis 底层相关的 epoll 的源码实现在 src/ae_epoll.c 文件中。
AIO 模型
异步非阻塞、由于操作系统完成后回调通知程序启动线程去处理,一般适用于链接较多且链接时间较长的应用。
应用场景:
AIO 方式适用于链接数目多且比较长(重操作),比如设备每间隔 2秒上报状态。
三种 I/O 模型对比
BIO | NIO | AIO | |
IO模型 | 同步阻塞 | 同步非阻塞(多路复用) | 异步非阻塞 |
编程难度 | 简单 | 复杂 | 复杂 |
可靠性 | 差 | 好 | 好 |
吞吐量 | 高 | 高 | 高 |