一、Netty介绍
Netty是一款用于高效开发网络应用的NIO网络框架
为什么选择Netty?
-
高性能,低延迟
Netty的I/O模型基于非阻塞I/O实现,底层依赖JDK NIO框架的多路复用器Selector。一个多路复用器Selector可以同时轮询多个Channel,采用epoll模式后,只需要一个线程负责Selector的轮询,接入成千上万的客户端基于Reactor模式进行事件分发,支持单Reactor、多线程Reacor和主从多线程Reactor,避免同步问题和多线程切换带来的资源消耗
-
弥补Java NIO的缺陷
JDK NIO的概念复杂,不具有易用性,Netty在NIO的基础上进行更高层次的封装,屏蔽了NIO的复杂性;Netty还提供了开箱即用的工具,包括行解码器、长度域解码器Netty更为稳定,解决了JDK NIO中较多的问题,包括:select空转导致CPU飙高、TCP断线重连、keep-alive检测等问题
扩展性高,可以通过参数配置定制化Reactor线程模型;基于事件驱动模型,分离框架层和业务层,开发者只需要关注ChannelHandler的业务逻辑实现
-
资源消耗低
内存池和对象池复用技术:通过内存池高效管理内存分配,通过对象池复用,避免频繁创建和销毁对象的开支零拷贝技术:包含操作系统级别的零拷贝技术,以及面向用户态的零拷贝技术。例如,I/O读写时直接使用DirectBuffer,避免了数据在堆内存和堆外内存之间的拷贝
二、常见的I/O模式
I/O请求的过程
I/O请求包含两个阶段,分布是:调用阶段和执行阶段
- 调用阶段:用户进程向内核发起系统调用
- 执行阶段:内核等待I/O请求处理完成返回。包含两个过程:首先等待数据就绪,写入内核缓冲去;再将内核缓冲区数据拷贝纸用户态缓冲区
5种I/O模式
- 阻塞和非阻塞:
阻塞与非阻塞主要体现在I/O未就绪时,操作系统对用户程序的处理。
如果操作系统挂起了用户程序,则为阻塞的方式;如果操作系统直接返回了未就绪状态给用户程序,则为非阻塞的方式。 - 同步和异步:
同步和异步体现在系统内核获取到的数据到底如何返回给应用层。
同步型的调用,应用层需要自己去向系统内核问询;异步型的调用,应用层无需主动向系统内核问询,在系统内核读取完文件数据之后,会主动通知应用层数据已经读取完毕,此时应用层即可以接收系统内核返回过来的数据,再做其他事情。
- 同步阻塞I/O(BIO)
应用进程向内核发起I/O请求,操作系统挂起应用进程,应用进程一致等待内核返回结果。一次完整的I/O请求称为BIO(Blocking IO,阻塞 I/O) - 同步非阻塞I/O(NIO)
引用进程向内核发起I/O请求,内核直接返回无数据,应用进程通过轮询的方式请求结果。缺点是轮询过程中大量的系统调用导致上下文切换开销很大。单独使用非阻塞I/O效率不高。 - I/O多路复用
多路指的是多个数据通道,复用指的是使用一个或固定多个线程来处理每一个socket。多路复用实现了一个线程处理多个I/O的操作,线程一次select调用可以获取内核中多个数据通道的数据状态。 - 信号驱动I/O
当数据准备就绪时,内核通过发送一个SIGIO信号通知应用进程,应用进程就可以读取数据了 - 异步I/O(AIO)
异步的特点在于从内核缓冲区拷贝数据到用户缓冲区的过程也是由系统异步完成的,应用进程只需要在特定的数组中引用数据即即可。