文章目录
- 一. 反应堆
- 1. 堵塞模型
- 2. Java NIO的工作原理
- 二. Netty与NIO
一. 反应堆
1. 堵塞模型
阻塞I/O在调用InputStream.read()方法时是阻塞的,它会一直等到数据到来(或超时)时才会返回;
同样,在调用ServerSocket.accept()方法时,也会一直阻塞到有客户端连接才会返回,每个客户端连接成功后,服务端都会启动一个线程去处理该客户端的请求。
阻塞I/O的通信模型示意如下图所示。
阻塞I/O通信模型的两个缺点。
- 当客户端多时,会创建大量的处理线程。且每个线程都要占用栈空间和一些CPU时间。(有些请求没有数据就会导致这些栈空间和cpu就会被一直占用ing)
- 阻塞可能带来频繁的上下文切换,且大部分上下文切换可能是无意义的。
上下文切换
CPU利用时间片轮询来为每个任务都服务一定的时间,然后把当前任务的状态保存下来,继续服务下一个任务。任务的状态保存及再加载叫做线程的上下文切换。
2. Java NIO的工作原理
- 由一个专门的线程来处理所有的I/O事件,并负责分发。
- 事件驱动机制:(不断地轮询判断事件是否到达)事件到的时候触发,而不是同步地去监视事件。
- 线程通信:(因为请求而建立的)线程之间通过wait、notify等方式通信(how)。保证每次上下文切换都是有意义的,减少无谓的(时间片进行)线程切换。
注:每个线程的处理流程大概都是读取数据、解码、计算处理、编码和发送响应。
二. Netty与NIO
Netty是一个异步的、事件驱动的、用来做高性能高可靠性的网络应用的框架。下面是其主要的优点。
(1)框架设计优雅,底层模型随意切换,适应不同的网络协议要求。
(2)提供了很多标准的协议、安全、编解码的支持。
(3)解决了很多NIO不易用的问题。
(4)社区更为活跃,在很多开源框架中使用,如Dubbo、RocketMQ、Spark等。
Netty支持的功能与特性如下图所示。
- 底层核心有:Zero-Copy-Capable Buffer,非常易用的零拷贝Buffer(这个内容很有意思,稍后专门来讲)、统一的API、标准可扩展的事件模型。
- 传输方面的支持有:管道通信;HTTP隧道;TCP与UDP。
- 协议方面的支持有:基于原始文本和二进制的协议;解压缩;大文件传输;流媒体传输;ProtoBuf编解码;安全认证;HTTP和WebSocket。
Netty采用NIO而非AIO的理由
- Netty不看重Windows上的使用,在Linux系统上,AIO的底层实现仍使用epoll,没有很好地实现AIO,因此在性能上没有明显的优势,而且被JDK封装了一层,不容易深度优化。
- Netty整体架构采用Reactor模型,而AIO采用Proactor模型,混在一起会非常混乱,把AIO也改造成Reactor模型,看起来是把Epoll绕个弯又绕回来。
- AIO还有个缺点是接收数据需要预先(你需要预估缓存)分配缓存,而NIO是需要接收时才分配缓存,所以对连接数量非常大但流量小的情况,AIO浪费很多内存。
- Linux上AIO不够成熟,处理回调结果的速度跟不上处理需求,比如外卖员太少,顾客太多,供不应求,造成处理速度有瓶颈。
参考:
《Netty4核心原理与手写RPC框架》