15 | Nio2Endpoint组件:Tomcat如何实现异步I/O?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
Tomcat如何实现异步I/O? 本文深入探讨了Tomcat如何利用Java NIO.2 API实现异步I/O。首先介绍了Java NIO.2 API的基本用法,包括创建线程池、异步通道群组和服务端异步通道,并绑定监听端口。重点关注了处理连接的回调类AcceptHandler和处理读的回调类ReadHandler的实现方式。通过具体的代码示例和清晰的解释,读者可以了解到在异步I/O模型中,应用程序向内核注册回调函数,当数据到达时,内核调用这些回调函数,同时提供一个线程池给内核使用,以提高处理速度。文章还解释了CompletionHandler接口的定义和使用,以及异步I/O模型的优势,强调了异步模式下应用程序不会被阻塞,从而提高了I/O通信的效率。另外,文章还介绍了Nio2Endpoint的组件设计和工作流程,以及Http11Processor的两次read调用来处理数据读取操作的方式。通过充分的抽象和巧妙的设计,Tomcat成功实现了协议处理器和I/O通信处理器之间的接口保持不变。总的来说,本文通过深入的技术讲解和实例分析,帮助读者全面了解了Tomcat如何实现异步I/O,以及Java NIO.2 API的异步I/O模型的工作原理和优势。
《深入拆解 Tomcat & Jetty 》,新⼈⾸单¥68
全部留言(44)
- 最新
- 精选
- -W.LI-老师好!Windows 的 IOCP 和 Linux 内核 2.6 的 AIO 都提供了异步 I/O 的支持,Java 的 NIO.2 API 就是对操作系统异步 I/O API 的封装。 这句话怎么理解啊?我看别的老师说Linux不支持异步IO,评论里也有同学说Linux下的AIO其实只是NIO之类的。老师能具体讲讲么谢谢。
作者回复: 刚我查了下JDK的源码,确实Java的NIO.2是通过epoll来模拟实现的,源码在这里: http://hg.openjdk.java.net/jdk9/dev/jdk/file/71716def08ac/src/java.base/linux/classes/sun/nio/ch/EPollPort.java Linux内核2.6确实提供了内核级的AIO支持,只是还不完善,详情可以看这里:http://lse.sourceforge.net/io/aio.html 估计是这个原因JDK没有使用这种方案。抱歉弄错了,还是不能人云亦云,一定要自己看了源码才行...
2019-06-18331 - -W.LI-老师好!那个两次read能理解为,连接被保留着,数据没就绪处理的线程资源先释放了。收到异步数据就绪通知后,根据原有的连接重建处理线程,继续处理。阻塞期间线程可复用
作者回复: 对的
2019-06-1818 - 王盛武李老师好,请问nio1,tomcat里nio为什么不参考netty,通过使用堆外内存来避免零拷贝问题?
作者回复: 主要还是堆外内存管理起来没有JVM堆那么方便,为了稳定性的考虑吧,另外APR就是堆外内存的方案,也就是已经提供了这个选项。
2019-06-1516 - J.M.Liu老师,NIO2中,由于TCP是一个流,那内核把多少字节拷贝到buff中才触发回调函数呢?比如一次http请求,有没有可能触发回调函数时,还没有把一个完整的http请求包接受完整呀?
作者回复: 对的,可能需要多次回调才能接收一个完整的请求
2019-08-21213 - 发条橙子 。老师 , 这两张讲的I/O有点难啃 ,主要还是底子太薄 。 反复看了几遍有几个疑问点希望老师指点一下 😄 1. read请求是怎么发出来的 是通过调用select方法发出来的么 ? 2. 异步我看发了一个read 就返回了,那实际是应该是指异步非阻塞 , 那么存在异步阻塞的模型么? 3. 老师说从tcp/ip那层解数据包。我理解的过程是 当客户端发一个uri请求,当通过一系列的路由后最终到我们的服务器,再从七层网络模型的最底层开始一路向上到最顶层的应用层。 当应用层(Tomcat容器)接收到请求(连接器endpoint监听端口)后向操作系统发送一个read请求 ,然后等待操作系统内核回调应用程序(Tomcat容器)的回调接口 。那么按照我这种脑补的过程,实际上当服务端tomcat接收到客户端的I/O请求时,向操作系统发送read请求要求操作系统将客户端发送的数据(前台的入参信息)从内核拷贝到用户空间。因为tcp/ip层在应用层下面,那么从网卡解析数据到内核这个过程是不是在tomcat获取到请求之前的的时候就已经处理好了,而不是在tomcat发送read请求时再去从网卡解析数据..?
作者回复: 1,select只是查询,真正发出read调用的还是read方法 2,好像没有异步阻塞这个说法 3,同步阻塞模型,read调用发起时,数据可能还没到网卡。如果io多路复用,read调用时,数据已经到了内核空间,因为之前select已经查到数据到了,应用才调read
2019-06-148 - yungoo我所看的tomcat 8.5的代码跟专栏所讲已经有些不一致了。已经没有Nio2Acceptor了,accept获取连接用的是Future aceept()。
作者回复: 我使用的是最新版的代码: https://github.com/apache/tomcat/blob/master/java/org/apache/tomcat/util/net/Nio2Endpoint.java#L382
2019-06-1338 - nimil问下老师,这个Tomcat这个IO模型是将数据拷贝了两次么,还是有做特殊优化
作者回复: 数据没有拷贝两次,第一次read调用是读不到数据的,因为这个时候数据还没应用层的Buffer,只是注册一个回调函数,当内核将数据拷贝到了应用层Buffer,调用回调函数,在回调函数里,HttpProccessor再发起一次read,read方法首先会检查数据是不是已经到了Buffer,如果是,直接读取Buffer返回,这一次并没有真正向内核发起read调用。
2019-06-137 - 802.11怎么模拟呢。现在springboot内置的Tomcat使用的都是nio 。设定NIO2呢
作者回复: 详细介绍 https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html
2019-06-2136 - z.llinux没有真正实现异步IO,所以linux环境下NIO和NIO2的性能差别是不是不大 ?
作者回复: 对的,NIO和NIO2其实差别不是很大,如果硬要区分,NIO适合处理比较轻的,数据传输量比较少的请求,AIO适合比较重,数据传输量比较大的请求。 这是因为NIO本质还是同步,数据从用户空间和内核空间之间的拷贝还是阻塞的。
2019-06-156 - 802.11Http11Processor的2次read是在哪个类中呢,没有找到。。。。
作者回复: Nio2SocketWrapper的read方法,这个方法会被调用两次,不是串行调两次,而是Poller会先后创建两个SocketProcessor任务类,在两个线程中执行,执行过程中每次Http11Processor都会调Nio2SocketWrapper的read方法。 public int read(boolean block, ByteBuffer to){ //第二次调用时直接通过这个方法取数据 int nRead = populateReadBuffer(to); ... //第一次时数据没取到,会调用下面这个方法去真正执行I/O操作并注册回调函数: nRead = fillReadBuffer(block); ... }
2019-06-156