I/O 的实际操作由内核执行, 其中一个重要手段是缓冲区. 简单来说 I/O 可分为两类: 面向磁盘和面向网络, Java 也是针对这两者来抽象设计 API, 相关的类主要在 java.io 和 java.nio 包中, 简称为 BIO 和 NIO.
为什么设计 NIO
一个直接原因就是为了更好的利用操作系统特性, 改善和扩展原有 API. 与 NIO 相关的规范有两个:
JSR 51 https://jcp.org/en/jsr/detail?id=51 : 它是 NIO 的第一个规范, 关注缓冲区, 通道和字符集的设计, 引入一个简单的面向缓冲区的 I/O 模型, 并且提供一套非阻塞, I/O 多路复用, 可扩展的 API;
JSR 203(NIO.2) https://jcp.org/en/jsr/detail?id=203 : 它在前者的基础上, 添加新的文件系统的抽象, 完善现有 Socket 通道的配置, 添加多播数据报的支持, 并且定义了一个异步 I/O 编程 API.
那么, 传统的 BIO 又有什么弊端? NIO 又是如何改进的?
文件操作
关于 java.io.file, 它的不足之处在于:
当查询文件属性时, 如修改时间或文件类型, 都会发生系统调用, 并且这些组合操作非常常见, 造成性能问题;
部分方法在发生错误时返回 false 而不是抛出异常, 比如 delete,rename;
一些 OS 常用功能不支持, 比如符号链接, 文件锁定, 内存映射等.
而 NIO 支持批量获取文件属性, 对文件, 目录的处理也重新设计, 提供 FileLock,MappedByteBuffer.
网络通信
传统 BIO 是阻塞式, 基于流的 I/O, 其网络服务器模型是一连接一线程, 通常采用线程池优化, 但一个进程或者计算机打开的线程数是有限的, 可扩展性差.
NIO 是基于缓冲区 (也是由字节流或字符流组成) 的, 对原始 I/O 提供了新的抽象 - Channel(通道).Channel 表示一个到硬件设备, 文件或网络套接字的连接, 与 java.net.Socket 的区别是:
可配置非阻塞, 允许事件驱动的设计, 提供了一种更加可扩展的服务器开发;
面向字节缓冲区, 可实现 零拷贝 https://www.ibm.com/developerworks/library/j-zerocopy/ 执行 I/O , 一端得是 FileChannel.
NIO 主要目标是设计, 开发可扩展 / 可伸缩性服务器, 让少量的线程管理大量的客户端连接, 而灵活的代价是编程复杂, 一复杂就会有人抽象出框架, NIO 常用的框架是 Netty, 这里想到一个问题, Netty 宣称的零拷贝与 OS 级别的有区别吗?
服务器常用的优化手段是对象池, 减少数据复制(内核到用户进程或用户进程内部), 减少上下文切换和锁, ByteBuffer 本质就是提供了一个可复用的 byte[] 数组, 而 BIO 做好这些优化也不见得比 NIO 慢, 那么如何选择 I/O 模型?
I/O 模型的选择
首先了解一下 C10k problem https://en.wikipedia.org/wiki/C10k_problem#cite_note-C10K-1 - 描述单机处理 1 万个并发连接的问题, 两个不同的概念:
并发连接(concurrent connections): 在有限的时间内响应请求, 关注高效的连接调度;
每秒请求数(requests per second): 快速处理请求以响应, 关注高吞吐量.
C10k 问题的本质在于 CPU, 即线程数, 单机创建大量线程, 不仅占用大量的内存, 频繁的数据复制和上下文切换还会导致 OS 崩溃.
如果采用 BIO 一个直观的解决办法是水平扩展, 采用分布式系统, 但如果并发量上升到百万, 千万, 甚至上亿, 那么服务器的成本得多大? 解决此问题的关键是减少线程数, 提高单机的处理能力, 而如何使用少量的线程管理大量的连接, 则在操作系统层面解决了, 也就是 Linux 下的 Epoll,Java 中的 NIO. 如果你的应用面临 C10k 问题, NIO 是最好的选择.
那 BIO 有什么用呢? 大家都用线程池, 你有 ByteBuffer, 我也可以自己维护字节缓冲, 照样成块读取, 阻塞无非因为 I/O 延迟高, 那换成 SSD 和光纤, 而且我编程简单, 唯一的缺点就是扩展性差了点.:)
至于如何选择 I/O 模型, 需要结合业务场景, 综合考虑:
短连接还是长连接
预计最大的并发数
预计每个连接的数据量, 即流量的大小
但感觉还是很难给出明确的答案, 简单来说, 并发量低的可采用 BIO, 高的可采用 NIO, 至于 AIO 它应该不太成熟, 不过多描述了.
小结
写的可能有点乱, 等以后有更多的体会, 再优化吧. 欢迎讨论.
来源: https://www.cnblogs.com/wskwbog/p/9360129.html