网络IO模型
网络IO模型 NIO,AIO 都由操作系统提供,应用程序通过调用不同的系统调用来决定使用 NIO 还是 AIO。
Blocking IO
系统调用
- 创建
监听socket
,得到 FD - 调用
bind
将监听socket
和 port 绑定 - 调用
listen
开始监听 - 调用
accept
阻塞等待 client 请求,返回已连接socket
的 FD - 调用
recv
阻塞等待 client 发送数据,返回收到的数据
缺点
阻塞IO模型下,1万个连接对应一万个 Thread:
- 大量等待 IO 数据就绪的 Thread 处于 WAIT 状态,浪费资源
- Java Thread 的实现是 LWP,上下文切换开销大
- JDK8 一个 Thread 占用 1MB 内存,这里就 9.7 GB,内存开销大
Non-Blocking IO
Reactor 模式,应用线程轮训 IO 事件,当 IO 就绪时,应用线程执行 IO读写、业务处理。
系统调用
select
监听发生在 FD 上的的事件,使 accept
、recv
可以立即完成,不会阻塞
poll
性能比 select
强
epoll_wait
性能比 poll
强
单 Reactor 单线程
Java 的 Selector 封装了 epoll 的系统调用,但 accept
、recv
还是由调用的线程执行,所以是同步的,但由于IO已经就绪,所以执行过程非阻塞。
单 Reactor 多线程
Netty 的 ServerBootstrap#group 设置一个 EventLoop 即可实现。
主从 Reactor 多线程
Netty 的 ServerBootstrap#group 设置两个独立的 EventLoop 即可实现。
Asynchronous IO
Proactor 模式,应用线程注册回调,当 IO 完成时,操作系统通知应用线程执行业务处理。
系统调用
Windows 提供 IOCP 实现 AIO
Linux 不支持 AIO
Java 提供 AsynchronousServerSocketChannel 模拟 AIO,使用复杂,高并发场景性能不如 NIO
Netty
Netty 是一款异步的事件驱动的网络应用程序框架。
异步
Netty 提供的异步接口,使用体验类似 AIO,但底层是 NIO
事件驱动
一种编程范式,程序的执行流由外部事件决定
parent\acceptor\boss\main
监听客户端连接,专门负责与客户端创建连接,并把连接注册到workerGroup的Selector中。
child\client\worker\sub
处理每一个连接发生的读写事件。
为什么高性能
- EpollEventLoopGroup、KQueueEventLoopGroup 基于 JNI 的本地方法实现,虽然不能跨平台,但高性能
- ByteBuf 使用了引用计数法回收堆外内存