js css html

Linux I/O模型详解以及Tomcat/Java/Netty

2023-03-04  本文已影响0人  王侦

1.I/O要解决什么问题?

I/O要解决什么问题?

以网络数据读取为例来分析,会涉及两个对象,一个是调用这个I/O操作的用户线程,另一个是操作系统内核。一个进程的地址空间分为用户空间和内核空间,基于安全上的考虑,用户程序只能访问用户空间,内核程序可以访问整个进程空间,只有内核可以直接访问各种硬件资源,比如磁盘和网卡。

1.1 文件数据读取

过程:

1.2 网络数据读取

当用户线程发起 I/O 调用后,网络数据读取操作会经历两个步骤:

2.I/O模型种类

在Linux中一共有5种I/O模型,分别如下:

2.1 blocking I/O

两阶段:

blocking I/O发起system call recvfrom()时,进程将一直阻塞等待另一端Socket的数据到来。在这种I/O模型下,我们不得不为每一个Socket都分配一个线程,这会造成很大的资源浪费。

Blocking I/O优缺点都非常明显。优点是简单易用,对于本地I/O而言性能很高。缺点是处理网络I/O时,造成进程阻塞空等,浪费资源。

注: read() 和 recvfrom()的区别是,前者从文件系统读取数据,后者从socket接收数据。

2.2 nonblocking I/O

两阶段:


相对于阻塞I/O在那傻傻的等待,非阻塞I/O隔一段时间就发起system call看数据是否就绪(ready)。

如果数据就绪,就从kernel space复制到user space,操作数据; 如果还没就绪,kernel会立即返回EWOULDBLOCK这个错误。

recvfrom有个参数叫flags,默认情况下阻塞。可以设置flag为非阻塞让kernel在数据未就绪时直接返回。详细见recvfrom

进程发起I/O操作时,不会因为数据还没就绪而阻塞,这就是”非阻塞”的含义。

2.3 I/O multiplexing (select 、poll、 epoll)

两阶段:

上面介绍的I/O模型都是直接发起I/O操作,而I/O Multiplexing首先向kernel发起system call,传入file descriptor和感兴趣的事件(readable、writable等)让kernel监测,当其中一个或多个fd数据就绪,就会返回结果。程序再发起真正的I/O操作recvfrom读取数据。

在linux中,有3种system call可以让内核监测file descriptors,分别是select、poll、epoll。

select:

poll:

epoll:

2.4 signal driven I/O (SIGIO)

两阶段:

看到它第一次发起system call不会阻塞进程,kernel的数据就绪后会发送一个signal给进程。进程发起真正的IO操作。

2.5 asynchronous I/O (the POSIX aio_functions)

两阶段:

2.6 总结对比


关键点一:IO分为两个阶段

关键点二:阻塞非阻塞与同步异步

3.开源组件支持的IO模型

3.1 Tomcat支持的 I/O 模型


注意: Linux 内核没有很完善地支持异步 I/O 模型,因此 JVM 并没有采用原生的 Linux 异步 I/O,而是在应用层面通过 epoll 模拟了异步 I/O 模型。因此在 Linux 平台上,Java NIO 和 Java NIO2 底层都是通过 epoll 来实现的,但是 Java NIO 更加简单高效。

3.2 Java共支持3种网络编程IO模式

3种网络编程IO模式

BIO:

NIO:

AIO:

3.3 为什么netty还要提供一个基于epoll的实现

自4.0.16起, Netty为Linux通过JNI的方式提供了native socket transport.

原因:

参考

上一篇 下一篇

猜你喜欢

热点阅读