在设计或重构系统的过程中,特别是在设计分布式、大数据量系统里面,序列化选型是一个重要环节,因为序列化协议影响系统的通用性、健壮性、安全性,是否易于调试、是否便于扩展。 序列化分理论和实践部分,理论部分描述只序列化是什么、要做什么,不关心实现(因为不考虑具体实现,所以自然不会考虑优缺点、应用场景);实践部分描述如何完成序列化操作,对象用什么方法表示,即把序列化从理论世界带进现实世界。序列化理论部分相当于是设计,实践部分相当于实现。
序列化理论包含的三个方面
1. 序列化问题是怎么产生的(序列化的定义)互联网的发展产生了机器之间互相通讯的需求,机器之间互相通讯需要约定通讯协议,通信协议又要考虑数据如何表示、如何传输等问题。序列化就是通信协议里与数据的表示相关的那一部分协议。OSI七层协议模型中的展现层(Presentation Layer)的主要功能是把对象转换成一段连续的二进制串,或把二进制串转换成对象–这就是序列化和反序列化。 所以,序列化和反序列化的定义就是:
注:不一定非要转换成二进制,只要是能传输到通信另一端都可以,例如utf-8字符串。 2. 序列化在通信协议中的地位
3. 序列化和反序列化的组件完整的序列化协议包含以下组件:
序列化组件之间的交互关系: 序列化组件之间的交互 序列化组件的概念与数据库的相关概念类似:
序列化协议的考虑点
已知的序列化协议互联网早期序列化协议有COM和CORBA。 COM主要用于Windows平台,没有实现跨平台。COM序列化利用了编译器中的虚表,使得学习成本很高。序列化得到的数据与编译器紧耦合,扩展属性非常麻烦。 CORBA比较好的实现了跨平台,跨语言。COBRA的主要问题是参与方过多,导致版本过多,版本之间兼容性差,使用复杂晦涩。早期设计的不成熟问题导致COBRA渐渐消亡。J2SE 1.3之后的版本提供基于CORBA协议的RMI-IIOP技术,可以采用纯Java语言进行CORBA开发。 当前比较流行的序列化协议有 XML、JSON、Protobuf、Hessian、Thrift、Avro。如果你还想了解更多序列化协议,参考 https://en./wiki/Comparison_of_data-serialization_formats XML序列化协议XML是一种语言,一种描述性的语言,最初目标是对文档进行编码,而且要求编码数据既能供人阅读也便于计算机处理。XML在设计的时候就考虑到可读性,它还有跨机器、跨语言(这里指的是人类语言)等优点。XML历史悠久,其1.0版本早在1998年就形成标准,并被广泛使用至今,所以XML是足够成熟的。既然XML能把有复杂结构的文档编码,那么XML也可以用于对象序列化,所以把XML列为一种序列化协议(例如.NET框架和gSOAP框架就采用XML序列化)。但是XML用作序列化协议的时候,它就显得冗长复杂。 XML具有自我描述性,XML自身就作为IDL。XML中的IDL(即XML描述格式)有两种:DTD(Document Type Definition)和XSD(XML Schema Definition)。XML在某些编程语言里面具有非常简单易用的序列化API,无需IDL文件和第三方IDL编译器(例如Java XStream)。XML被广泛应用在各种配置文件中,例如O/R mapping、 Spring Bean Configuration File 等。 优点:跨平台、跨语言、成熟、可读性 缺点:复杂冗长(空间复杂度) SOAP序列化协议SOAP(Simple Object Access protocol)是一种广泛应用的,基于XML的结构化消息传递协议,XML被用于序列化和反序列化。SOAP支持多种传输协议,但是最常用的还是HTTP。SOAP协议的IDL是WSDL(Web Service Description Language)。 假如java应用层对象是: 用WSDL描述上述对象: SOAP具有安全、可扩展、跨语言、跨平台、支持多种传输协议,有广泛的群众基础,基于HTTP的传输协议使得SOAP在穿越防火墙时具有良好安全性,XML的人眼可读特性使得其具有出众的可调试性,互联网带宽的发展逐渐弥补了其空间开销大的缺点。对于在公司之间传输少量数据或实时性要求相对低(例如秒级别),SOAP是一个好的选择。 XML空间开销大,数据量大、需要持久化应用场景不适合用XML。XML的序列化和反序列化的空间和时间开销都比较大,对于对性能要求达到ms级别的服务,不推荐XML。WSDL虽然具备对象描述能力,但是SOAP的使用不简单。对于习惯于面向对象编程的用户,WSDL文件不直观。 JSON序列化协议权威网站:http:/// JSON起源于JavaScript中的”Associative array”的概念,本质就是采用”Attribute-value”方式描述对象。实际上在Javascript和PHP等弱类型语言中,类的描述方式就是Associative array。JSON有如下优点,使得它快速成为最广泛使用的序列化协议之一: 1、这种Associative array格式匹配工程师对对象的理解。 2、它也有XML的人眼可读(Human-readable)优点。 3、序列化后的数据简洁。 4、JavaScript先天支持,所以广泛应用于Web browser的应用常景,是Ajax的事实标准协议。 5、与XML相比,其协议比较简单,解析速度比较快。 6、松散的Associative array使得其具有良好的可扩展性和兼容性。 因为json其实是associative array,与弱类型编程语言中的class在概念上对应,所以JSON序列化也不需要IDL。原因:IDL的目的是撰写IDL文件,而IDL文件被IDL Compiler编译后产生一些代码(Stub/Skeleton),而这些代码真正负责相应的序列化和反序列化工作。 但是由于Associative array和一般语言里面的class太相似,他们之间形成了一一对应关系,这就使得我们可以采用一套标准代码进行相应的转化。对于自身支持Associative array的弱类型语言,语言自身就具备操作JSON序列化后的数据的能力;对于Java这强类型语言,可以用反射解决。 JSON在很多应用场景中可以替代XML,更简洁且解析速度更快。典型应用场景包括:
总体看,JSON序列化的额外空间开销也比较大(但是比XML小多了),不适合数据量大或需要持久化的场景。没有统一的IDL降低了对参与方的约束,实际操作中往往只能采用文档方式来进行约定,这可能会给调试带来一些不便,延长开发周期。由于JSON在一些语言中的序列化和反序列化需要反射机制,所以性能要求ms级别的系统不建议使用。 Thrift序列化协议Thrift是Facebook开发的一个RPC框架,满足了大数据量、分布式、跨语言、跨平台数据通讯的需求。Thrift内部有一个自定义的序列化协议,即Thrift序列化协议。 优点:相对于JSON和XML,Thrift在空间开销和解析性能上有较大提升,适用于性能要求高的系统;它支持多种编程语言,数据类型丰富,对于数据字段的增删有较强的兼容性。 缺点:thrift序列化被嵌入到thrift框架内部,然而Thrift框架没有对外提供thrift序列化和反序列化的接口,文档匮乏,用起来比较困难。Thrift序列化之后得到的数据是Binary数组,不具有可读性,调试相对困难。Thrift的序列化和框架紧耦合,无法支持向持久层直接读写数据,不适合用于数据持久化的场景。 Protobuf序列化协议权威网站:https://developers.google.com/protocol-buffers Protobuf具备序列化协议的众多优秀特征:
Protobuf是一个纯展示层协议,可以用于多种传输层协议;Protobuf文档也非常完善。目前仅支持Java、C++、Python三种编程语言。另外Protobuf支持的数据类型较少,不支持常量。 所以Protobuf适用于跨公司、性能要求高的RPC调用应用场景。基于相同的原因,Protobuf也适合用于对象的持久化。 缺点:支持语言较少,没有绑定标准传输层协议,跨公司进行传输层协议调试相对麻烦。 Google gPRC框架已采用Protobuf序列化协议,可以参考。 Hessian序列化协议hessian也是一种常见的序列化协议,经常在RPC框架中使用,例如Dubbo、Pigeon等框架都支持Hessian,甚至经常被RPC框架用作默认序列化方案。 Avro序列化协议Avro是Apache Hadoop的子项目,解决了JSON的冗长和没有IDL的问题。Avro提供两种序列化格式:JSON格式和Binary格式。Binary格式在空间开销和解析性能方面可以和Protobuf媲美,JSON格式方便调试。Avro支持的数据类型非常丰富,包括C++语言里面的union类型。Avro支持JSON格式的IDL和类似于Thrift和Protobuf的IDL(实验阶段),这两者之间可以互转。Schema可以在传输数据的同时发送,加上JSON的自我描述属性,使得Avro非常适合动态类型语言。Avro在做文件持久化的时候,一般会和Schema一起存储,所以Avro序列化文件自身具有自我描述属性,所以适合做Hive、Pig和MapReduce的持久化数据格式。对于不同版本的Schema,在进行RPC调用的时候,服务端和客户端可以在握手阶段对Schema进行互相确认,提高了数据解析的速度。Avro解析性能高且序列化数据简洁,适合高性能序列化服务。 序列化协议Benchmark数据 https://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking 解析性能 序列化之空间开销 1、XML序列化(Xstream)无论在性能和简洁性上都比较差。 2、Thrift与Protobuf相比在时空开销方面都有一定劣势。 3、Protobuf和Avro在两方面表现都非常优越。 序列化协议的选型以上几种序列化协议各自具有特点,适用于不同场景: 1、公司之间系统调用,性能要求100ms,基于XML的SOAP协议是一个值得考虑的方案。 2、基于Web browser的Ajax,以及移动app与服务端之间的通讯,JSON是首选。对于性能要求不高或者以动态类型语言为主,传输数据小的场景,JSON是非常不错的选择。 3、对于调试环境比较恶劣的场景,JSON或XML能够极大的提高调试效率,降低开发成本。 4、当对性能和简洁性有极高要求的场景,可以考虑Protobuf、Thrift、Avro。 5、对于T级别的数据的持久化应用场景,Protobuf和Avro是首选。如果持久化后的数据存储在Hadoop子项目里,Avro是更好的选择。 6、Avro的设计理念偏向于动态类型语言,对于动态语言为主的应用场景,Avro是更好的选择。 7、持久层非Hadoop项目,以静态类型语言为主的场景,Protobuf更符合开发习惯。 8、如果需要提供一个完整的RPC解决方案,Thrift是一个好的选择。 9、如果序列化之后需要支持不同传输协议,或需要跨防火墙访问,Protobuf可以优先考虑。 参考资料
|
|
来自: 启云_9137 > 《计算机及软件应用》