Netty介绍及应用

Posted 京东虚拟平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Netty介绍及应用相关的知识,希望对你有一定的参考价值。

    在JAVA领域的网络通信,我们会想到应用层的HTTP协议和传输层的TCP协议。基于HTTP会简单些,因为它解决了基于TCP实现需要解决的一些问题,比如拆包、粘包,但是它性能差:半双工、文本传输、繁重的数据包头等,所以追求高效的网络通信通常会选择基于TCP的通信实现。TCP通信我们可以选择BIO阻塞式实现,也可以选择NIO非阻塞式实现(当然还有AIO)。NIO我们可以选择JDK自带的API也可以选择NIO框架。NIO框架我们可以选择Netty、MINA或者Grizzly(基于JDK API实现),这里我们介绍Netty,之前先介绍下相关基础知识。

基础知识

 I/O模型


Unix提供了五种I/O模型:阻塞I/O,非阻塞I/O,I/O复用,信号驱动I/O,异步I/O。JDK并没有五种对应的实现,JDK1.4之前的ServerSocket属于阻塞I/O,1.4引入了NIO的包,提供了Channel、Buffer和Selector等,其中Selector就是多路复用的实现,它通过把多个I/O的阻塞复用到同一个Select的阻塞上,从而可以实现单线程的情况下同时处理多个客户端请求。1.7引入的NIO2.0提供更加完善的AIO功能。当然JDK提供的这些功能在底层都依赖操作系统的实现。


  零拷贝


    在我们进行I/O操作的时候无论是文件I/O还是网络I/O,传统的实现都会存在数据在内核空间和用户空间的传输。为什么会存在内核空间和用户空间?因为操作系统为了保证自身的安全和稳定进行了这样的划分,普通进程是不能直接使用内核空间的,而底层的操作又依赖操作系统,所以有了这种数据的复制。比如一个典型的数据流向(读取硬盘数据并通过网络发送):


    如果我们的应用程序并不需要对数据进行操作,步骤2和3显然是需要优化的,所以有了零拷贝技术。零拷贝就是一种避免 CPU 将数据从一块存储拷贝到另外一块存储的技术,具体实现上有mmap()、sendfile()等。

Netty 简介

Netty

1

Trustin Lee 写的一个nio框架(mina也是他的作品,但是Netty更晚些)。方便我们快速开发高性能、高可靠的网络服务器和客户端程序。


2

Netty并不像Grizzly那样基于JDK的NIO来实现,它重写了大部分底层的实现,比如Channel和ByteBuf,同时也依赖JDK NIO,比如分配直接内存时,调用的就是JDK的API。


3

Netty 的API简单、开发门槛低,不像JDK NIO那样繁杂。功能强大预设了多种编解码功能(各种ChannelHandler)。性能高、成熟稳定(解决了jdk的epoll bug)。社区活跃、大规模商业应用考验。


Netty 核心模块


Netty介绍及应用

ByteBuf

    JDK的ByteBuffer结构如左图,由于没有单独标识读写数据的指针,在调用read()或write()方法之前需要调用flip(),clear()方法来进行读写之前的切换,如果忘了则会调用错误的数据。而netty的ByteBuf 在结构上(右图)进行了重新设计,读写分别有readIndex和writeIndex位置指针,直接调用读写方法就行,不需要相关的重置操作。


Netty介绍及应用
Netty介绍及应用

    而具体实现上按空间类型分类有HeapByteBuf和DirectByteBuf。Heap就是在普通的堆空间进行分配,而Direct是直接内存(基于mmap,api层面通过UnSafe开辟),避免了数据在内核空间和用户空间无效的拷贝。直接内存是块特殊的空间,它的大小不受Xmx的限定,也不由GC回收。

Netty介绍及应用

Channel

    Channel是Netty网络操作的抽象,聚合了一组功能,包括但不限于网络的读写,客户端发起连接,主动关闭连接。实现:NioserverSocketChannel(tcp传输服务端)、NioSocketChannel(tcp传输)、DatagramChannel(udp传输)


Netty介绍及应用

ChannelPipeline和ChannelHandler


ChannelPipeline和ChannelHandler机制类似Servlet和Filter过滤器,这类拦截器实际上是职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定制。ChannelHandler是我们业务逻辑实现的地方。他们关系如下:


Netty介绍及应用

    Netty预设了一些ChannelHandler来供开发人员使用。比如用于处理拆包、粘包的LineBasedFrameDecoder、FixedLengthFrameDecoder和LengthFieldBasedFrameDecoder等。序列化和反序列化的ProtobufEncoder/ProtobufDecoder等。还有实现长连接的IdleStateHandler。


EventLoop/EventLoopGroup


    从类的继承关系上看它们和线程池相关。根据用户的启动参数,可以同时支持reactor单线程模型,reactor多线程、主从等模型。单线程模型是指所有的I/O操作都在同一个NIO线程上面完成。多线程与单线程最大的区别就是有一组NIO线程来处理I/O操作(单独的NIO线程来监听服务端监听客户端的tcp链接请求,读写由一个NIO线程池负责)。主从则是用一个线程池来处理与客户端的链接,如果链接上有很多业务逻辑的处理,比如:登录、握手、安全认证,显然一个线程是应付不过来的。


总结与应用

    Netty主要负责底层通信,它的功能远不止上面介绍的这些。在java没有引入nio或aio之前,底层高性能通信主要是c或c++的天下,而现在我们可以多种选择了。


    既然Netty用于网络通信,所以涉及通信的地方就可以考虑使用Netty,比如web服务器、websocket、消息中间件及RPC框架等。京东的RPC框架JSF,阿里的消息中间件RocketMQ底层通信都有用Netty(RPC是主动调用的模式,消息中间件是推送模式),还有美团点评的实时监控系统CAT等等,说明netty在底层高效通信还是久经考验的,这里介绍下在RPC框架实现中的使用。

    RPC (Remote Procedure Call ) 远程方法调用,它不是一种新的技术,只是应用框架的解决方案而已,比较纯粹的解决进程间的通信。比如webservice的SOAP或REST是RPC,京东的jsf、阿里的dubbo、腾讯的tars、facebook的thrift和google的grpc也是RPC的实现。thrift、grpc和tars他们可以跨语言,所以需要IDL来标准化需要传输的对象。也不要太拘泥于概念,明白他们的本质就行。除了可以使用一些开源的RPC框架,我们自己如何实现RPC呢?这里介绍下使用Netty实现的RPC,黄勇(git@github.com:luxiaoxun/NettyRpc.git),李业兵(git@github.com:Hulk904/ares-remoting.git)都是基于Netty实现的RPC框架,可以供我们学习的demo。尽管离生产平台的RPC有些差距,但麻雀虽小五脏俱全。

框架结构如下:


其底层通信都是用Netty来实现,流程也类似

1

服务端启动并注册服务

2

客户端获取服务提供信息并组装请求参数

3

序列化请求参数向服务端请求等待响应结果

4

服务端获取结果并反序列化

5

反射调用服务实现

6

封装结果并序列化响应给客户端

7

客户端反序列化获取结果

以上是关于Netty介绍及应用的主要内容,如果未能解决你的问题,请参考以下文章

Netty框架之责任链模式及其应用

Netty框架之概述及基本组件介绍

Netty

Day466.Netty介绍和应用场景 -netty

Day466.Netty介绍和应用场景 -netty

谈京东京麦TCP网关的Netty应用实践