Netty

11/20/2019 Netty

# Netty简介

Netty 是由 JBOSS 提供的一个 java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用 Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 socket 服务开发。

“快速”和“简单”并不用产生维护或性能上的问题。Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

Netty 从 4.x 版本开始,需要使用 JDK1.6 及以上版本提供基础支撑。

在设计上:针对多种传输类型的统一接口 - 阻塞和非阻塞;简单但更强大的线程模型;真正的无连接的数据报套接字支持;链接逻辑支持复用

在性能上:比核心 Java API 更好的吞吐量,较低的延时;资源消耗更少,这个得益于共享池和重用;减少内存拷贝

在健壮性上:消除由于慢,快,或重载连接产生的 OutOfMemoryError;消除经常发现在 NIO 在高速网络中的应用中的不公平的读/写比

在安全上:完整的 SSL / TLS 和 StartTLS 的支持且已得到大量商业应用的真实验证,如:Hadoop 项目的 Avro(RPC 框架)、Dubbo、Dubbox等 RPC 框架。

# Netty 架构

img

# Netty线程模型

img

# 线程模型详解

Netty 中支持单线程模型,多线程模型,主从多线程模型。

# Reactor单线程模型

是指所有的I/O操作都在同一个NIO线程上完成,职责如下

  • 作为NIO服务端,接收客户端TCP连接
  • 作为NIO客户端,向服务端发起TCP连接
  • 读取对端请求或者应答消息
  • 向对端发送请求或者应答消息

img

在一些小容量场景下,可以使用多线程模型,但对于高负载场景下并不适用,原因如下:

  • 一个NIO线程同时处理成百上千的连接,性能上无法保证。
  • NIO线程负载过重,处理速度会越来越慢,会导致大量客户端连接超时
  • 一旦NIO线程跑飞,或者死循环,会导致整个系统的不可用

# Reactor多线程模型

img

与单线程模型最大的区别是,有一组NIO来处理I/O请求,特点如下

  • 有一个NIO线程——Acceptor线程用户监听客户端的连接
  • 有一个NIO线程池负责I/O的读写操作,该线程池可以是基于JDK的线程池。

# 主从Reactor多线程模型

img

如果并发百万的客户端连接,在Reactor多线程模型下只有一个NIO的Acceptor线程处理客户端连接会有性能问题。主从Reactor线程模型的特点是:服务端用于接收客户端的连接不再是一个单独的NIO线程,而是一个NIO的Acceptor线程池。Acceptor接收到客户端的TCP连接请求处理完成后,将新创建的ChannelSocket注册到I/O线程池(sub reactor线程池)上的某一个线程上,由I/O负责后续的I/O读写操作。

# 快速入门

4.x版本传送门 (opens new window)

# 流数据的传输处理

在基于流的传输里比如 TCP/IP,接收到的数据会先被存储到一个 socket 接收缓冲里。不幸的是,基于流的传输并不是一个数据包队列,而是一个字节队列。即使你发送了 2 个独立的数据包,操作系统也不会作为 2 个消息处理而仅仅是作为一连串的字节而言。因此这是不能保证你远程写入的数据就会准确地读取。所以一个接收方不管他是客户端还是服务端,都应该把接收到的数据整理成一个或者多个更有意思并且能够让程序的业务逻辑更好理解的数据。

在处理流数据粘包拆包时,可以使用下述处理方式:

  • 使用定长数据处理,如:每个完整请求数据长度为 8 字节等。(FixedLengthFrameDecoder)
  • 使用特殊分隔符的方式处理,如:每个完整请求数据末尾使用’\0’作为数据结束标记。(DelimiterBasedFrameDecoder)
  • 使用自定义协议方式处理,如:http 协议格式等。
  • 使用 POJO 来替代传递的流数据,如:每个完整的请求数据都是一个 RequestMessage对象,在 Java 语言中,使用 POJO 更符合语种特性,推荐使用。