随分布式架构、微服务架构的流行,一个支持高并发、高性能、易扩展的网络系统,其背后必定是由大量服务器所组成的集群在提供服务。服务器集群之间的数据通信则需要通过网络来建立。Netty是一款异步的事件驱动的网络应用程序框架,支持快速地开发可维护的高性能的面向协议的服务器和客户端。目前,已有许多基于netty实现的分布式架构,并且在生产环境中展现了netty在性能、稳定性、扩展性等方面的优异。本文旨在简要介绍netty的初步印象。
linux的IO操作方式
linux操作系统分为内核态和用户态,用户对磁盘、网络等外设的调用操作,都可以被当做是对文件进行操作。用户进程想要操作文件则都需要通过内核进行,这就相当于一个IO操作需要从用户态处理到内核态处理至少两步操作。一个完整的IO操作需要在用户态到内核态的来回切换,这几种操作组合就带来了多种IO模型。
根据IO的请求发出到结果完成,期间用户进程是否可以处理其他业务,我们区分为阻塞和非阻塞;根据将IO的数据从硬盘或网络中读取到用户内存中的操作过程,是由用户进程操作还是由用户进程请求之后由操作系统完成加载到内存,区分为同步和异步。
因此我们的操作系统的IO模型被分为:同步阻塞、同步非阻塞和异步非阻塞三种。我们用一个例子来说明,比如我们用水瓶去开水房打热水(类比用户进程从文件或网络中取数据),有排队打水的同学(其他用户进程),开水房还有一个维护秩序的大爷(操作系统内核),我们的水瓶就类比用户进程的内存,开水房里的热水就是数据。
同步阻塞:我们自己排队并接水完成,期间从进开水房到出开水房,干不了其他事,这种就是同步阻塞;就是用户进程IO请求之后,就一直等待并阻塞进程直至处理完成(接水完成),模型交互图如:

同步非阻塞:我们告诉开水房里的大爷,我们要接水,让他给我们看着前面可以接水了,就通知我们自己去用水瓶接水,我们就可以去干其他事,等他通知我们可以接水了,我们再去接水;就是用户发出IO请求之后,可以处理其他业务,待内核将数据准备好之后,通知用户进程,用户进程再读取IO数据并处理,模型交互图如:

异步非阻塞:我们把开水瓶给大爷,然后就去干其他事,他帮我们把水接好,然后通知我们拿走水瓶;就是用户发出IO请求之后,可以处理其他业务,并且由操作系统将数据加载到用户内存中,并通知用户,交互图如:

netty基于原生NIO提供更好的网络IO封装
对于IO操作,jdk提供同步阻塞的api,和NIO的非阻塞模型。因为同步阻塞模型在支持并发操作时会很容易到达瓶颈,所以目前服务器端通常使用基于NIO的设计。
netty封装网络IO的通用功能。在进行网络应用服务开发时,有很多需要解决的网络问题,比如原生NIO就有一定的概率出现epoll空轮询的bug,并且网络应用必须要处理网络连接异常,网络资源释放等问题。Netty通过封装底层的网络通用处理功能,解决了原生NIO可能出现的epoll空轮询bug,并且对于各种网络异常,进行了处理,由此让应用开发人员可以更专注于业务逻辑的开发。
提供网络IO需解决的通用扩展接口。网络数据进行发送传递时,都是以数据包的形式进行分发专递,而在这个过程中,可能会出现数据包被拆分或者与其他无关数据进行了组合传递,所以我们需要解决tcp粘包、拆包的问题,而netty则提供了多种解决粘包拆包的接口,数据编解码的接口等。值得借鉴的是,netty在提供这些接口之外,还可以方便的支持用户自定义的实现,用户可以方面的进行扩展。
netty核心组件
Channel 接口 :基本操作IO(bind、connect、read、write操作),提供了大量的接口,如NioSocketChannel、NioDatagramChannel等。)
EventLoop:一个EventLoopGroup 包含一个或多个EventLoop,一个EventLoop在它的生命周期中只和一个Thread绑定,一个Channel在它的生命周期内只注册一个EventLoop,一个EventLoop可能会被分配一个或多个Channel,而EventLoop处理IO的事件都是由绑定的Thread所处理,因此同一个Channel的操作实际是由一个线程完成的避免了线程切换;
ChannelHandler接口:所有需要对数据流进行拦截处理的逻辑可以通过实现和定义ChannelHandler来实现,将处理逻辑如事件拦截器,数据的编解码、tcp的粘包拆包处理 依次添加在ChannelPipeline管道中,数据流流经管道,就会做对应处理;
ChannelPipeline接口:抽象数据流的管道,并将IO操作抽象为事件,ChannelPipeLine接口为ChannelHandler链提供一组操作链,可以在pipeline中注册一连串的事件处理逻辑;
数据缓冲区ByteBuf:初始化缓冲区的三种方式,划分堆内存缓冲区、划分直接内存缓冲区、复合缓冲区(题外话:很多实现方案是从一种极端和另一种极端之间的选择,从其中找到平衡点兼而有之)
netty设计理念值得借鉴
使用build模式创建连接实例;
使用façade模式封装Channel接口,提供对外统一接口;
面向抽象,将网络中IO的接入、读取等抽象为事件,监听事件。
责任链模式设计ChannelPipeline