基于Netty的RPC通信系统的编解码技术研究

来源 :电脑知识与技术 | 被引量 : 0次 | 上传用户:jwk000
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘要:近年来,面向服务的体系架构(SOA)逐渐成为构建大中型分布式系统的主流方式,远程过程调用(RPC)在其中起着举足轻重的作用。Netty作为一个基于事件驱动的、异步的网络应用框架,能够快捷高效的实现分布式系统间的远程服务调用。该文对Netty编解码器进行分析和研究,并结合消息序列化,提出了一种性能和可靠性更高的编解码方法。
  关键词:netty;编解码;序列化;远程过程调用;消息协议
  中图分类号:TP311.5 文献标识码:A 文章编号:1009-3044(2017)26-0104-02
  Abstract: In recent years, service oriented architecture (SOA) has gradually become the mainstream way to build large and medium-sized distributed systems. Remote procedure call (RPC) plays an important role in it. Netty, as an event driven and asynchronous network application framework, can quickly and efficiently realize remote service invocation among distributed systems. In this paper, the Netty codec is analyzed and studied, and a method of encoding and decoding with higher performance and reliability is proposed combining with message serialization.
  Key words: netty;serialization; codec; remote procedure call; message protocol
  SUN公司在2002年推出了JDK1.4,基于Java的Socket通信开始支持非阻塞I/O,系统性能和可靠性均得到了很大的提高。但早期的API和类库依然存在一些不完善的地方,特别是对文件系统的处理能力非常薄弱。直到2007年JDK1.7发布,升级后的NIO2.0提供了异步文件通道和异步套接字通道的实现,文件处理能力有了进一步的提升[1-2]。尽管NIO的吞吐量和可靠性相对于传统的BIO(同步阻塞式IO)有了质的飞跃,但其类库和API十分繁杂,使用起来非常困难[3]。再加上粘包拆包、断线重连等可靠性处理的工作量和复杂度都非常大,因此不建议使用NIO原生API进行通信系统的开发。为了简化NIO网络编程,一些开源组织发布了诸如Netty、Mina、Grizzly和xSocket等通信框架。其中,Netty的功能、性能、健壮性、可定制和可扩展行在同类框架中都是首屈一指的,并且已经得到了大量商业项目的成功验证,如阿里巴巴的分布式服务框架Dubbo,Hadoop的RPC框架Avro等[4]。本文基于Netty框架,定义了一种通用的消息结构Message,继承Netty的半包解码器LengthFieldBaseFrameDecoder解码消息以解決TCP粘包拆包问题,使用protobuf对消息体进行序列化,使通信系统的性能和可靠性均得到了极大的提高。
  1 编解码方法
  1.1 粘包拆包问题
  由于应用层发送消息时写入的字节大小不固定以及IP分片等原因,TCP底层会根据缓冲区的实际情况将单个业务消息拆分成多个包,或者将多个小包封装成一个大包进行发送。接收方有可能一次接收不完整个业务消息或者一次收到几个消息,此时消息解码就会出现异常,不能进行接下来的业务处理和消息回应。TCP粘包拆包无法在底层进行规避,只能通过合理的上层应用协议设计进行处理[5]。常用的解决方案有三种:一是消息定长;二是使用特殊字符对消息进行分割;三是将消息分为消息头和消息体,在消息头中存储消息长度。第一种方案在消息封装上不够灵活,固定创建的缓冲区长度必须大于最长的消息长度,因此在写入较短的消息时会造成资源浪费。第二种方案中使用特殊字符分割消息,如果消息本身就包含了该字符,则不能正确进行解码,存在一定的局限性。本文采用第三种方案,使用消息头描述消息长度。接收方先读取固定长度的消息头,获取其中包含的消息长度,根据消息长度再次(或多次)读取相应长度的字节即读完整个消息,将包中余下的字节缓存起来作为下一个消息的前一部分。
  1.2 消息结构定义
  消息分为消息头和消息体两个部分。消息头固定长度,用来描述消息的类型、长度和优先级等信息。消息体可变长度,承载消息实体。具体定义如表1和表2。
  1.3 继承半包解码器
  根据上文对消息结构的定义,本文将业务整包消息定义为4个部分。如图1所示,HDR1中包含标识符和版本号,HDR2中包含会话ID、消息类型和消息优先级,Length和ActualContent分别表示数据帧长度和数据内容。定义MessageDecoder继承半包解码器LengthFieldBasedFrameDecoder实现粘包拆包处理。在其构造方法中设置lengthFieldOffset=8(长度字段偏移的字节数)、lengthFieldLength=4(数据帧长度)、lengthAdjustment=10(长度字段调整长度)和initialBytesToStrip=12(数据帧跳过字节数)。实际的长度字段偏移位置等于in.readerIndex()加上lengthFieldOffset,读取消息长度字段所占的4个字节表示的数值即为消息长度。通常情况下再次读取Length长度的字节就能获取完整的消息,通过lengthAdjustment和initialBytesToStrip对消息长度进行调整。
其他文献
如何开展高职院校计算机基础教育,培养出适应市场需求的高等职业技术人才,是整个高职教育面临的课题.本文从分析现状入手,在教材体系的建立、教学模式的转变等方面论述了高职