一起来学习Netty的传输吧

613 阅读5分钟

这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战

一、传输API

  传输API的核心是interface Channel,它被用于所有的I/O操作。Channel类的层次结构如下图所示:

image.png   每个Channel都将会被分配一个ChannelPipeline和ChannelConfig。ChannelConfig包含了该Channel的所有配置设置,并且支持热更新。
  由于Channel是独一无二的,所以为了保证顺序将Channel声明为java.lang.Comparable的一个子接口。因些,如果两个不同的Channel实例都返回了相同的散列码,那么AbstractChannel中的CompareTo()方法的实现将会抛出一个Error。
  ChannelPipeline持有所有将应用于入站和出站数据以及事件的ChannelHandler实现,这些ChannelHandler实现了应用程序用于处理状态变化以及数据处理的逻辑。

  ChannelHandler的典型用途包括:

  • 将数据从一种格式转换为另一种格式;
  • 提供异常的通知;
  • 提供Channel变为活动的或者非活动的通知;
  • 提供当Channel注册到EventLoop或者从EventLoop注销时的通知;
  • 提供有关用户自定义事件的通知   Netty的Channel实现是线程安全的,因此可以存储一个到Channel的引用,并且每当你需要向远程节点写数据时,都可以使用它,即使当时许多线程都在使用它。

二、内置的传输

  Netty内置了一些可开箱即用的传输,但它们并不是所有的传输协议都支持,所以必须选择一个和你的应用程序所使用的协议相容的传输。下表显示所有的Netty提供的传输。

名  称描  述
NIOio.netty.channel.socket.nio使用java.nio.channels包作为基础——基于选择器的方式
Epollio.netty.channel.epoll由JNI驱动的epoll()和非阻塞IO。这个传输支持只有Linux上可用的多种特性,如SO_REUSEPORT,比NIO传输更快,而且是完全非阻塞的
NIOio.netty.channel.socket.nio使用java.nio.channels包作为基础——基于选择器的方式
OIOio.netty.channel.socket.oio使用java.net包作为基础——使用阻塞流
Localio.netty.channel.local可以在VM内部通过管道进行通信的本地传输
Embeddedio.netty.channel.embeddedEmbedded传输,允许使用ChannelHandler而又不需要一个真正的基于网络的传输。这在测试你的ChannelHandler实现时非常有用

2.1 NIO——非阻塞I/O

  NIO提供了一个所有I/O操作的全异步的实现。它利用了自NIO子系统被引入JDK1.4时便可用的基于选择器的API。
  选择器背后的基本概念是充当一个注册表,在那里你将可以请求在Channel的状态发生变化时得到通知。可能的状态变化有 :

  • 新的Channel已被接受并且就绪(对应的状态集OP_ACCEPT)
  • Channel连接已经完成(对应的状态集OP_CONNECT)
  • Channel有已经就绪的可供读取的数据;(对应的状态集OP_READ)
  • Channel可用于写数据(对应的状态集OP_WRITE)   选择器运行在一个检查状态变化并对其做出相应响应的线程上,在应用程序对状态的改变做出响应之后,选择器将会被重置,并将重复这个过程。

  对于所有Netty的传输实现都共有的用户级别API完全地隐藏了这些NIO的内部细节。下图展示了该处理流程。

image.png

2.2 Epoll——用于Linux的本地非阻塞传输

  Netyy的NIO传输基于Java提供的异步/非阻塞网络编程的通用抽象。虽然这保证了Netty的非阻塞API可以在任何平台上使用,但它也包含了相应的限制,因为JDK为了在所有系统上提供相同的功能,必须做出妥协。
  Linux作为高性能网络编程的平台,其重要性与日俱增,这催生了大量先进特性的开发,其中包括epoll—— 一个高度可扩展的I/O事件通知特性。这个API自Linux内核版本2.5.44(2002)被引入,提供了比旧的POSIX select和poll系统调用更好的性能,同时现在也是Linux上非阻塞网络编程的事实标准。Linux JDK NIO API使用了这些epoll调用。如果你的应用程序旨在运行于Linux系统,那么请考虑利用这个版本的传输;你将发现在高负载下它的性能要优于JDK的NIO实现。

2.3 OIO——旧的阻塞I/O

  Netty的OIO传输实现代表了一种折中:它可以通过常规的传输API使用,但是由于它是建立在java.net包的阻塞实现之上的,所以它不是异步的。但是,它仍然非常适合于某些用途。   下图是NettyOIO传输的流程:

image.png

2.4 用于JVM内部通信的Local传输

  Netty提供了一个Local传输,用于在同一个JVM中运行的客户端和服务器程序之间的异步通信。同样,这个传输也支持对于所有Netty传输实现都共同的API。

2.5 Embedded传输

  Netty提供了一种额外的传输,使得你可以将一组ChannelHandler作为帮助器类嵌入到其他的ChannelHandler内部。通过这种方式,你将可以扩展一个ChannelHandler的功能,而又不需要修改其内部代码。