[Netty 1] 初识Netty

2019-03-02 23:41|来源: 网路

1. 简介

最早接触netty是在阅读Zookeeper源码的时候,后来看到Storm的消息传输层也由ZMQ转为Netty,所以决心好好来研究和学习一下netty这个框架。

Netty项目地址:http://netty.io/index.html 

Github项目: https://github.com/netty/netty

Netty是一个异步的、事件驱动的网络应用框架,基于它能够快速开发高性能协议的服务器和客户端。Netty是基于NIO的,它大大简化了网络编程,Netty强调“quick and easy“,但并不仅限于”quick and easy“,它的实现是建立在吸取了许多协议(FTP、SMTP、HTTP等)的实现经验的基础之上的,经过作者精心的设计探索,成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。

2. 架构介绍

netty的架构图:

 

 我们可以看到主要有三大部分组成:Core、Transport Services和Protocol Support。

2.1 Core

Core封装了底层通信接口并提供了一个抽象的可扩展的事件模型。

2.1.1 Zero-Copy-Capable Rich Byte Buffer

netty基于NIO,但是它并没有使用NIO的ByteBuffer,而是使用了自己定义的Buffer: ChannelBuffer。这是Netty用来表示二进制或文本消息的最基本的数据结构。 ChannelBuffer类型的设计从底层解决了ByteBuffer的问题,并能够满足日常网络应用开发。它相比ByteBuffer有着明显的优势,主要体现在:

  • 允许自定义缓冲类型
  • 基于内置复合缓冲类型实现透明的零拷贝
  • 提供开箱的动态缓冲类型,容量可以根据需要扩充,这点跟StringBuffer很类似
  • 不再需要调用flip()方法
  • 通常会比ByteBuffer更快

 至于每一点的详细介绍,请参考官方文档: http://docs.jboss.org/netty/3.2/api/org/jboss/netty/buffer/package-summary.html#package_description

2.1.2 Universal Communication API

传统的Java I/O API在应对不同的传输协议时需要使用不同的类型和方法。例如,java.net.Socket 和 java.net.DatagramSocket它们并不具有相同的超类型,因此,这就需要使用不同的调用方式执行socket操作。

这种模式上的不匹配使得在更换一个网络应用的传输协议时变得繁杂和困难。由于(Java I/O API)缺乏协议间的移植性,当你试图在不修改网络传输层的前提下增加多种协议的支持,这时便会产生问题。并且理论上讲,多种应用层协议可运行在多种传输 层协议之上例如TCP/IP,UDP/IP,SCTP和串口通信。
让这种情况变得更糟的是,Java新的I/O(NIO)API与原有的阻塞式的I/O(OIO)API并不兼容,NIO.2(AIO)也是如此。由于所有的API无论是在其设计上还是性能上的特性都与彼此不同,在进入开发阶段,你常常会被迫的选择一种你需要的API。
例如,在用户数较小的时候你可能会选择使用传统的OIO(Old I/O) API,毕竟与NIO相比使用OIO将更加容易一些。然而,当你的业务呈指数增长并且服务器需要同时处理成千上万的客户连接时你便会遇到问题。这种情况下 你可能会尝试使用NIO,但是复杂的NIO Selector编程接口又会耗费你大量时间并最终会阻碍你的快速开发。
Netty有一个叫做Channel的统一的异步I/O编程接口,这个编程接口抽象了所有点对点的通信操作。也就是说,如果你的应用是基于Netty的某一种传输实现,那么同样的,你的应用也可以运行在Netty的另一种传输实现上。Netty提供了几种拥有相同编程接口的基本传输实现:

  • NIO-based TCP/IP transport (See org.jboss.netty.channel.socket.nio),
  • OIO-based TCP/IP transport (See org.jboss.netty.channel.socket.oio),
  • OIO-based UDP/IP transport, and
  • Local transport (See org.jboss.netty.channel.local).

切换不同的传输实现通常只需对代码进行几行的修改调整,例如选择一个不同的ChannelFactory实现。
此外,你甚至可以利用那些还没有写入的新的传输协议,只需替换一些构造器的调用方法即可,例如串口通信。而且由于核心API具有高度的可扩展性,你还可以完成自己的传输实现。

2.1.3 Extensible Event Model

Netty框架是基于事件驱动的,所以设计一个良好的具有很好的可扩展性的事件模型是非常必要的。

Netty具有定义良好的I/O事件模型。由于严格的层次结构区分了不同的事件类型,因此Netty允许你在不破坏现有代码的情况下实现自己的事件类 型,这是与其他框架相比另一个不同的地方。很多NIO框架没有或者仅有有限的事件模型概念;在你试图添加一个新的事件类型的时候常常需要修改已有的代码, 或者根本就不允许你进行这种扩展。
在一个ChannelPipeline内部一个ChannelEvent被一组ChannelHandler处理。因此对于一个事件如何被处理以及管道内部处理器间的交互过程,你都将拥有绝对的控制力。

有关事件模型的更多信息,参考API文档中的ChannelEventChannelPipeline部分。

2.2 Transport Services 和 Protocol Support

上述所提及的核心组件已经足够实现各种类型的网络应用,除此之外,Netty也提供了一系列的高级组件来加速你的开发过程。

2.2.1. Codec框架

从业务逻辑代码中分离协议处理部分总是一个很不错的想法。然而如果一切从零开始便会遭遇 到实现上的复杂性。你不得不处理分段的消息。一些协议是多层的(例如构建在其他低层协议之上的协议)。一些协议过于复杂以致难以在一台主机(single state machine)上实现。

因此,一个好的网络应用框架应该提供一种可扩展,可重用,可单元测试并且是多层的codec框架,为用户提供易维护的codec代码。
Netty提供了一组构建在其核心模块之上的codec实现,这些简单的或者高级的codec实现帮你解决了大部分在你进行协议处理开发过程会遇到的问题,无论这些协议是简单的还是复杂的,二进制的或是简单文本的。

2.2.2. SSL / TLS 支持

不同于传统阻塞式的I/O实现,在NIO模式下支持SSL功能是一个艰难的工作。你不能只是简单的包装一下流数据并进行加密或解密工作,你不得不借助于 javax.net.ssl.SSLEngine,SSLEngine是一个有状态的实现,其复杂性不亚于SSL自身。你必须管理所有可能的状态,例如密 码套件,密钥协商(或重新协商),证书交换以及认证等。此外,与通常期望情况相反的是SSLEngine甚至不是一个绝对的线程安全实现。
在Netty内部,SslHandler 封装了所有艰难的细节以及使用SSLEngine可能带来的陷阱。你所做的仅是配置并将该SslHandler插入到你的ChannelPipeline中。同样Netty也允许你实现像StartTlS 那样所拥有的高级特性,这很容易。

2.2.3.  HTTP实现

HTTP无疑是互联网上最受欢迎的协议,并且已经有了一些例如Servlet容器这样的HTTP实现。因此,为什么Netty还要在其核心模块之上构建一套HTTP实现?
与现有的HTTP实现相比Netty的HTTP实现是相当与众不同的。在HTTP消息的低层交互过程中你将拥有绝对的控制力。这是因为Netty的 HTTP实现只是一些HTTP codec和HTTP消息类的简单组合,这里不存在任何限制——例如那种被迫选择的线程模型。你可以随心所欲的编写那种可以完全按照你期望的工作方式工作 的客户端或服务器端代码。这包括线程模型,连接生命期,快编码,以及所有HTTP协议允许你做的,所有的一切,你都将拥有绝对的控制力。
由于这种高度可定制化的特性,你可以开发一个非常高效的HTTP服务器,例如:

  •  要求持久化链接以及服务器端推送技术的聊天服务(e.g. Comet
  •  需要保持链接直至整个文件下载完成的媒体流服务(e.g. 2小时长的电影)
  •  需要上传大文件并且没有内存压力的文件服务(e.g. 上传1GB文件的请求)
  •  支持大规模mash-up应用以及数以万计连接的第三方web services异步处理平台
2.2.4. Google Protocol Buffer 整合

Google Protocol Buffers 是快速实现一个高效的二进制协议的理想方案。通过使用 ProtobufEncoderProtobufDecoder,你可以把Google Protocol Buffers 编译器(protoc)生成的消息类放入到Netty的codec实现中。请参考官方示例中的“LocalTime”示例,这个例子也同时显示出开发一个由简单协议定义的客户及服务端是多么的容易。

2.3. 总述

在这一章节,我们从功能特性的角度回顾了Netty的整体架构。Netty有一个简单却不失强大的架构。这个架构由三部分组成——缓冲(buffer), 通道(channel),事件模型(event model)——所有的高级特性都构建在这三个核心组件之上。一旦你理解了它们之间的工作原理,你便不难理解在本章简要提及的更多高级特性。

 

参考: http://blog.sina.com.cn/s/blog_3fe961ae01011oob.html


转自:http://www.cnblogs.com/wxpjimmy/p/3712819

相关问答

更多
  • netty如何使用[2022-05-14]

    和spring , 先写一个类,然后与一般的bean同样配置
    我假设您仍想与Camel集成。 我先来看看骆驼文档 。 在此之后,你需要开始尝试。 我有一个例子,我创建了一个Camel处理器作为Netty服务器。 Netty组件的工作原理是From端点是消耗的服务器,To端点是生成的客户端。 我需要一个To端点,它是一个服务器,组件不支持它。 我只是将Camel Processor实现为一个Spring bean,它在初始化时启动了Netty Server。 JBoss Netty文档和示例非常好。 值得一提的是。 这是我瘦身的例子。 它是一个向所有连接的客户端发送消息 ...
  • 您只需覆盖messageReceived即可处理消息。 如果你想要一些“特殊”处理,你可以“覆盖”其他人。 You only need to override messageReceived to process messages. You "can" override others if you want some "special" handling.
  • 在阅读了相当庞大的Netty资源的一部分之后,我已经用一些仔细应用的Proguard规则解决了这个问题: -keepattributes Signature,InnerClasses -keepclasseswithmembers class io.netty.** { *; } -keepnames class io.netty.** { *; } 我原来的异常是由字节码中的类型变量引起的,Netty通过反射来使用字节码。 -keepattributes Signature保留这些信息。 ...
  • 在这篇文章中你可以找到你回答,在Netty 3.X中,这些包来自org.jboss.netty。* http://netty.io/3.10/api/index.html 但是从Netty 4.X开始,包装来自io.netty。*参见: http ://netty.io/4.0/api/index.html 是的,版本3和版本4有几个不同之处。 我建议您使用稳定版本进行开发,请在http://netty.io/wiki/index.html中查看 In this post you could find yo ...
  • ProxyHandler不支持HTTP1 / 1。 No the ProxyHandler does only support HTTP1/1.
  • Spark使用Akka Actor进行RPC和消息传递,而后者使用Netty。 另外,为了移动批量数据,使用Netty。 对于混洗数据,可以选择使用Netty。 默认情况下,NIO直接用于传输洗牌数据。 对于广播数据(驾驶员对所有员工的数据传输),默认情况下使用Jetty。 Spark uses Akka Actor for RPC and messaging, which in turn uses Netty. Also, for moving bulk data, Netty is used. For ...
  • netty的异步来自哪里? Netty采用了你可能从JavaScript这样的语言中得知的eventloops原理。 这允许netty完全异步工作。 (有关eventloops和基本原理的更多信息,我会推荐这个关于JavaScript中的evenloop的视频 ) 客户端需要什么来从异步获益? 客户端发送请求(包含有效负载和请求id = clientside递增整数) 服务器处理请求50秒 服务器发送响应(包含有效载荷和客户端在其请求中发送的相同请求ID) 客户端收到响应并查找请求标识(如果客户端能够找到请 ...
  • 将byte[]传递给Netty write方法相当于传递未加密的ByteBuf 。 我们可以在ByteArrayEncoder的源代码中看到这一点,它在内部调用Unpooled#wrappedBuffer(byte[]) : @Override protected void encode(ChannelHandlerContext ctx, byte[] msg, List out) throws Exception { out.add(Unpooled.wrappedBuffer( ...
  • 在我发布问题后不久找到答案。 我需要使用频道上提供的属性映射: http://netty.io/wiki/new-and-noteworthy.html Found the answer shortly after I posted my question. I need to use the attribute map available on the Channel: http://netty.io/wiki/new-and-noteworthy.html