请选择 进入手机版 | 继续访问电脑版

默认
打赏 发表评论 11
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
微信扫一扫关注!

1、前言


从JDK 7版本开始,Java新加入的文件和网络io特性称为nio2(new io 2, 因为jdk1.4中已经有过一个nio了),包含了众多性能和功能上的改进,其中最重要的部分,就是对异步io的支持,称为Java AIO(asynchronous IO)。

因为AIO的实施需充分调用OS参与,IO需要操作系统支持、并发也同样需要操作系统的支持,所以性能方面不同操作系统差异会比较明显。所以本文也附带介绍了Linux 2.6及以后版本新增的AIO特性(因为这跟Java AIO是对应关系)。

* 相关文章:另一篇提到AIO的大型应用架构实践的文章。《从0到1的快速裂变:详解快的打车架构设计及技术实践

* 本文已于2021年12月9日重新优化排版。

2、Java AIO


2.1基本原理


目前为止,Java共支持3种网络编程模型:BIO、NIO、AIO:

  • 1)Java BIO : 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善;
  • 2)Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理;
  • 3)Java AIO(NIO.2) : 异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。

BIO、NIO、AIO适用场景分析:

  • 1)BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解;
  • 2)NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持;
  • 3)AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

2.2AIO介绍


jdk在1.4版本的nio中提供了对非阻塞多路复用同步io模型的支持,但是在Windows上是基于较低效select/poll实现的。

jdk1.7中提供对aio的支持后,带来了两方面的好处:

  • 1)Windows上可以使用iocp了;
  • 2)简化了网络变成模型。异步io相比较非阻塞多路复用模型更易理解,开发更为简单。

和多路复用的java nio相比较,可以发现,异步io是在数据读取或者写入调用已经完成的时候,再通知调用者,而非阻塞多路复用io则是在有数据就绪,可以读写的时候通知调用者,读写仍然是由调用者执行并且是阻塞的(这意味着如果要同时进行其他工作,要控制读写操作不能阻塞太长时间或者需要将其放去单独的io线程执行)。

JDK7中的java aio新增的类和接口主要有:

  • 1)AsynchronousServerSocketChannel :对应于bio中的ServerSocket和nio中的ServerSocketChannel,用于server端的网络程序;
  • 2)AsynchronousSocketChannel:对云关于bio中的Socket和nio中的SocketChannel,用于client端的网络程序;
  • 3)CompletionHandler:回调接口,在socket进行accept/connect/read/write等操作时,可以传入一个CompletionHandler的实现,操作执行完毕后,会调用注册的CompletionHandler。

除了CompletionHandler这种回调方式,aio中还支持返回Future对象,使用Future来设定回调操作。

3、Linux AIO


3.1Linux AIO 简介


Linux 异步 I/O 是 Linux 内核中提供的一个相当新的增强。它是 2.6 版本内核的一个标准特性,但是我们在 2.4 版本内核的补丁中也可以找到它。AIO 背后的基本思想是允许进程发起很多 I/O 操作,而不用阻塞或等待任何操作完成。稍后或在接收到 I/O 操作完成的通知时,进程就可以检索 I/O 操作的结果。

3.2Linux 的 I/O 模型


在深入介绍 AIO API 之前,让我们先来探索一下 Linux 上可以使用的不同 I/O 模型。这并不是一个详尽的介绍,但是我们将试图介绍最常用的一些模型来解释它们与异步 I/O 之间的区别。图 1 给出了同步和异步模型,以及阻塞和非阻塞的模型。

基本 Linux I/O 模型的简单矩阵:
11.png

每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序都有自己的优点。

3.2.1)同步阻塞 I/O:

如下图所示:传统的阻塞 I/O 模型,这也是目前应用程序中最为常用的一种模型。其行为非常容易理解,其用法对于典型的应用程序来说都非常有效。在调用 read 系统调用时,应用程序会阻塞并对内核进行上下文切换。然后会触发读操作,当响应返回时(从我们正在从中读取的设备中返回),数据就被移动到用户空间的缓冲区中。然后应用程序就会解除阻塞(read 调用返回)。

QQ20160514-0.png

从应用程序的角度来说,read 调用会延续很长时间。实际上,在内核执行读操作和其他工作时,应用程序的确会被阻塞。

3.2.2)同步非阻塞 I/O:

同步阻塞 I/O 的一种效率稍低的变种是同步非阻塞 I/O。在这种模型中,设备是以非阻塞的形式打开的。这意味着 I/O 操作不会立即完成,read 操作可能会返回一个错误代码,说明这个命令不能立即满足(EAGAIN 或 EWOULDBLOCK),如下图所示。

33.png

非阻塞的实现是 I/O 命令可能并不会立即满足,需要应用程序调用许多次来等待操作完成。

这可能效率不高,因为在很多情况下,当内核执行这个命令时,应用程序必须要进行忙碌等待,直到数据可用为止,或者试图执行其他工作。正如图 3 所示的一样,这个方法可以引入 I/O 操作的延时,因为数据在内核中变为可用到用户调用 read 返回数据之间存在一定的间隔,这会导致整体数据吞吐量的降低。

3.2.3)异步阻塞 I/O:

另外一个阻塞解决方案是带有阻塞通知的非阻塞 I/O。

在这种模型中,配置的是非阻塞 I/O,然后使用阻塞 select 系统调用来确定一个 I/O 描述符何时有操作。使 select 调用非常有趣的是它可以用来为多个描述符提供通知,而不仅仅为一个描述符提供通知。对于每个提示符来说,我们可以请求这个描述符可以写数据、有读数据可用以及是否发生错误的通知。

QQ20160514-1.png

select 调用的主要问题是它的效率不是非常高。尽管这是异步通知使用的一种方便模型,但是对于高性能的 I/O 操作来说不建议使用。

3.2.4)异步非阻塞 I/O(AIO):

最后,异步非阻塞 I/O 模型是一种处理与 I/O 重叠进行的模型。读请求会立即返回,说明 read 请求已经成功发起了。在后台完成读操作时,应用程序然后会执行其他处理操作。当 read 的响应到达时,就会产生一个信号或执行一个基于线程的回调函数来完成这次 I/O 处理过程。

55.png

在一个进程中为了执行多个 I/O 请求而对计算操作和 I/O 处理进行重叠处理的能力利用了处理速度与 I/O 速度之间的差异。当一个或多个 I/O 请求挂起时,CPU 可以执行其他任务;或者更为常见的是,在发起其他 I/O 的同时对已经完成的 I/O 进行操作。

3.3异步 I/O(AIO) 的动机


从前面 I/O 模型的分类中,我们可以看出 AIO 的动机。这种阻塞模型需要在 I/O 操作开始时阻塞应用程序。这意味着不可能同时重叠进行处理和 I/O 操作。

同步非阻塞模型允许处理和 I/O 操作重叠进行,但是这需要应用程序根据重现的规则来检查 I/O 操作的状态。这样就剩下异步非阻塞 I/O 了,它允许处理和 I/O 操作重叠进行,包括 I/O 操作完成的通知。

除了需要阻塞之外,select 函数所提供的功能(异步阻塞 I/O)与 AIO 类似。不过,它是对通知事件进行阻塞,而不是对 I/O 调用进行阻塞。

4、本文小结


使用异步 I/O(AIO)可以帮助我们构建 I/O 速度更快、效率更高的应用程序。如果我们的应用程序可以对处理和 I/O 操作重叠进行,那么 AIO 就可以帮助我们构建可以更高效地使用可用 CPU 资源的应用程序。

尽管这种 I/O 模型与在大部分 Linux 应用程序中使用的传统阻塞模式都不同,但是异步通知模型在概念上来说却非常简单,可以简化我们的设计。

附录:更多高性能网络编程资料


[1] NIO异步网络编程:
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
有关“为何选择Netty”的11个疑问及解答
开源NIO框架八卦——到底是先有MINA还是先有Netty?
选Netty还是Mina:深入研究与对比(一)
选Netty还是Mina:深入研究与对比(二)
NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
Netty 4.x学习(一):ByteBuf详解
Netty 4.x学习(二):Channel和Pipeline详解
Netty 4.x学习(三):线程模型详解
Apache Mina框架高级篇(一):IoFilter详解
Apache Mina框架高级篇(二):IoHandler详解
MINA2 线程原理总结(含简单测试实例)
Apache MINA2.0 开发指南(中文版)[附件下载]
MINA、Netty的源代码(在线阅读版)已整理发布
解决MINA数据传输中TCP的粘包、缺包问题(有源码)
解决Mina中多个同类型Filter实例共存的问题
实践总结:Netty3.x升级Netty4.x遇到的那些坑(线程篇)
实践总结:Netty3.x VS Netty4.x的线程模型
详解Netty的安全性:原理介绍、代码演示(上篇)
详解Netty的安全性:原理介绍、代码演示(下篇)
详解Netty的优雅退出机制和原理
NIO框架详解:Netty的高性能之道
Twitter:如何使用Netty 4来减少JVM的GC开销(译文)
绝对干货:基于Netty实现海量接入的推送服务技术要点
长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结
新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略
少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别
史上最强Java NIO入门:担心从入门到放弃的,请读这篇!
手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制
Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!
史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战
长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
>> 更多同类文章 ……

[2] 网络编程(高阶):
高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少
高性能网络编程(二):上一个10年,著名的C10K并发连接问题
高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了
高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索
高性能网络编程(五):一文读懂高性能网络编程中的I/O模型
高性能网络编程(六):一文读懂高性能网络编程中的线程模型
高性能网络编程(七):到底什么是高并发?一文即懂!
不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)
不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)
不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT
不为人知的网络编程(四):深入研究分析TCP的异常关闭
不为人知的网络编程(五):UDP的连接性和负载均衡
不为人知的网络编程(六):深入地理解UDP协议并用好它
不为人知的网络编程(七):如何让不可靠的UDP变的可靠?
不为人知的网络编程(八):从数据传输层深度解密HTTP
不为人知的网络编程(九):理论联系实际,全方位深入理解DNS
不为人知的网络编程(十):深入操作系统,从内核理解网络包的接收过程(Linux篇)
不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密
不为人知的网络编程(十二):彻底搞懂TCP协议层的KeepAlive保活机制
不为人知的网络编程(十三):深入操作系统,彻底搞懂127.0.0.1本机网络通信
长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
从根上理解高性能、高并发(一):深入计算机底层,理解线程与线程池
从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术
从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用
从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步
从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程
从根上理解高性能、高并发(六):通俗易懂,高性能服务器到底是如何实现的
从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

标签:网络编程 AIO
上一篇:理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程下一篇:传输层安全协议SSL/TLS的Java平台实现简介和Demo演示

本帖已收录至以下技术专辑

推荐方案
评论 11
真心学习一下
认真学习
签名: ········
据说Linux不支持AIO?
引用:blinnn 发表于 2018-11-29 17:41
据说Linux不支持AIO?

你说的恰恰相反吧
签名: 有点累,这周不想发新文了哦
认真学习了
所以 netty 的epoll kqueue 指的是 异步还是同步非阻塞IO呢
我觉得是异步非阻塞
上一篇 讲到的异步或者同步  对象除了指的是被调用者 (作为主体) 还要指名 调用者是否需要立即返回的结果(结果)
这点也很重要!!!
区别于阻塞和非阻塞指的是调用者 发起IO请求(可以指的是上层http请求)到调用者收到结果之前的这段时间,调用者是否不能做其他事情(被阻塞)
引用:xiaobin 发表于 2019-03-18 22:11
所以 netty 的epoll kqueue 指的是 异步还是同步非阻塞IO呢
我觉得是异步非阻塞
上一篇 讲到的异步或者 ...

学的很认真
签名: 有点累,这周不想发新文了哦
引用:xiaobin 发表于 2019-03-18 22:11
所以 netty 的epoll kqueue 指的是 异步还是同步非阻塞IO呢
我觉得是异步非阻塞
上一篇 讲到的异步或者 ...

我认为netty的实现是异步阻塞,也就是他宣传的NIO。netty尝试过AIO的实现,但是后来放弃了,据netty的同学说是AIO性能提升不明显。
不懂就问;所以异步阻塞就是IO复用?但是这个文章说同步阻塞...
还是说其实同步、异步、阻塞、非阻塞都需要分层对待?例如网卡到内核空间的异步的,但是内核空间到用户空间是同步的? WX20210805-114948@2x.png
最后异步I/O(AIO)的动机
引用:这种阻塞模型需要在 I/O 操作开始时阻塞应用程序。这意味着不可能同时重叠进行处理和 I/O 操作。

这句话指的是BIO吧
引用:Rayman 发表于 2021-08-05 11:50
不懂就问;所以异步阻塞就是IO复用?但是这个文章说同步阻塞...
还是说其实同步、异步、阻塞、非阻塞都需 ...

我感觉他有两处弄反了
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部