我正在阅读使用Java序列化的弊端,以及使用序列化框架的必要性。有很多框架,例如avro,镶木地板,节俭,protobuff。
问题是,什么框架处理选择序列化框架时要考虑的参数以及所有参数。
我想动手实践一个用例,并根据需求比较/选择序列化框架。
有人可以在这个主题上提供协助吗?
有很多因素需要考虑。我将介绍一些重要的知识。
0]架构优先或代码优先
如果您有一个涉及不同语言的项目,那么代码优先方法可能会出现问题。很好,它都有一个可以序列化的JAVA类,但是如果必须在C中反序列化,可能会很麻烦。
为了防止万一,我通常赞成使用模式优先方法。
1)对象间描述
某些序列化产生字节流,可以看到一个对象在哪里停止而另一个在哪里开始。其他不要。
因此,如果您有一个消息传输/数据存储,它将为您分离出几批字节,例如ZeroMQ或数据库字段,则可以使用不标记消息的序列化。示例包括Google协议缓冲区。通过由传输/存储完成的标记,读取器可以获得一批字节,知道该字节肯定包含一个对象,并且仅包含一个对象。
如果您的邮件传输/数据存储区在批处理字节之间未指定,例如网络流或文件,那么您要么发明自己的标记,要么使用为您标记的序列化。示例包括ASN.1 BER,XML。
[2)规范
这是序列化的属性,这意味着序列化的数据具有其自身的结构。原则上,规范消息的阅读者不必事先知道消息的结构是什么,它可以在读取字节时简单地算出(即使它不知道字段名称)。在您不完全确定数据来自何处的情况下,这很有用。如果数据不是规范的,则读者必须事先知道对象结构是什么,否则反序列化是不明确的。
标准序列化的示例包括ASN.1 BER,ASN.1标准PER,XML。不包含ASN.1 uPER的,可能是Google协议缓冲区(我可能有错)。
AVRO做一些不同的事情-数据模式本身就是序列化数据的一部分,因此始终可以从任意数据中重建对象。如您所见,在像C这样的语言中,用于此目的的库有些笨拙,而在动态语言中则更好。
3)大小和值受限。
某些序列化技术允许开发人员对字段的值和数组的大小设置约束。目的是从包含此类约束的模式文件生成的代码将在序列化和反序列化时自动验证对象。
这可能非常有用-自动完成由模式驱动的免费内容检查。找出不合规格的数据非常容易。
这在大型异构项目(正在使用多种不同的语言)中非常有用,因为关于有效内容和非有效内容的所有真相来源都来自模式,只有模式,并且由自动生成的自动强制执行码。开发人员不能忽略/绕过约束,而当约束发生变化时,每个人都会不禁注意到。
[示例包括ASN.1(通常通过工具集做得很好),XML(免费/廉价工具集通常做不到; MS的xsd.exe故意忽略任何此类约束)和JSON(具体到对象验证器)。在这三者中,ASN.1到目前为止是最详尽的约束语法。它真的非常强大。
没有的示例-Google协议缓冲区。在这方面,GPB非常令人恼火,因为它完全没有约束。具有值和大小限制的唯一方法是将它们写为.proto文件中的注释,并希望开发人员阅读并注意它们,或者采用其他非源代码方法。由于GPB非常针对异质系统(实际上支持太阳下的每种语言),因此我认为这是一个非常严重的遗漏,因为必须为项目中使用的每种语言手动编写值/大小验证代码。那是浪费时间。 Google可以在.proto和代码生成器中添加语法元素,以支持此功能,而根本不更改导线孔(全部在自动生成的代码中)。
4)二进制/文本
二进制序列化会更小,序列化/反序列化可能会更快一些。文本序列化更易于调试。但是使用二进制序列化可以完成的事情令人惊讶。例如,您可以轻松地将ASN.1解码器添加到Wireshark(使用ASN.1工具从.asn模式文件进行编译),也可以在对程序数据进行有线解码时使用。我应该想到,GPB也有可能。
ASN.1 uPER在带宽受限的情况下非常有用;它自动使用大小/值约束来节省线路上的位。例如,在0到15之间有效的字段仅需要4位,这就是uPER将使用的位。我应该想到,uPER在3G,4G和5G之类的协议中具有很高的功能也不是巧合。这种“最少位数”的方法比压缩文本线格式要优雅得多(这是使用JSON和XML所做的很多工作,以使它们不那么肿)。
5)值
这有点奇怪。在ASN.1中,模式文件既可以定义对象的结构,也可以定义对象的值。使用更好的工具,您最终得到(在C ++,JAVA等源代码中)类,并预定义已经用值填充的该类的对象。
为什么这么有用?好吧,我经常使用它来定义项目常量,并获得约束的限制。例如,假设您在消息中得到一个有效长度为15的数组字段。您可以在字段约束中使用文字15,或者可以在约束中引用一个整数对象的值,并且整数也可供开发人员使用。在要遍历该约束的情况下,这真的很方便,因为该循环可以是
for (int i = 0; i < ArraySize; i++) {do things with field[i];} // ArraySize is an integer in the auto generated code built from the .asn schema file
显然,如果需要更改约束,这是很了不起的,因为必须更改约束的唯一位置是在架构中,然后进行项目重新编译(使用该位置的每个位置都将使用新值)。更好的是,如果在架构文件中将其重命名,则重新编译会在使用它的对象中的任何地方进行标识(因为使用它的开发人员编写的源代码仍然使用旧名称,现在它是未定义的符号->编译器错误。] >
据我所知,只有ASN.1这样做。然后,只有更昂贵的工具才能从架构文件中实际选择这些元素。有了它,这使得它在大型项目中非常有用,因为与数据及其约束以及如何处理数据相关的所有内容实际上都仅在.asn模式中定义,而在其他任何地方都没有定义。
正如我说过的,我经常使用这种类型的正确项目。一旦它遍及整个项目,节省的时间和风险就非常可观。它也改变了项目的动力。知道整个项目只需要重新编译就可以对模式进行后期更改。因此,在项目后期更改协议会从高风险变为您每天可能会满意的事情。
6)线格式对象类型
某些序列化线格式将以线格式字节数识别对象的类型。这在许多不同类型的对象可能来自一个或多个源的情况下为读者提供了帮助。其他序列化不会。
ASN.1从有线格式变化到有线格式(它有几种,包括一些二进制的以及XML和JSON)。 ASN.1 BER在其线格式中使用类型,值和长度字段,因此读者有可能预先窥视对象的标签,从而对字节流进行相应的解码。这非常有用。
[Google Protocol Buffers并没有做同样的事情,但是如果.proto中的所有消息类型都捆绑到一个最终的oneof
中,并且只有每个序列化,那么您就可以实现同一件事
[7)工具成本。
ASN.1工具的范围从非常非常昂贵(非常好)到免费(却不太好)。许多其他工具都是免费的,尽管我发现最好的XML工具(适当注意值/大小约束)也很昂贵。
[8)语言覆盖率
[如果您听说过,很可能会被许多不同语言的工具所涵盖。如果没有,那就更少了。
良好的商业ASN.1工具涵盖了C / C ++ / Java / C#。有一些免费的C / C ++,它们的完整性各不相同。
9)质量
如果工具的质量很差,那么采用串行化技术是不好的。
[根据我的经验,GPB是很好的(通常会按照它说的那样做)。商业ASN1工具非常出色,全面超越了GPB的工具集。 AVRO的作品。我听说Capt'n Proto有时会出现问题,但是我自己没有使用过,则必须检查一下。 XML使用好的工具。
10)摘要
如果您不知道,我非常喜欢ASN.1。
GPB对其广泛的支持和熟悉度也非常有用,但是我希望Google能够为字段和数组添加值/大小约束,并且还包含一个值符号。如果他们这样做,将有可能拥有与ASN.1相同的项目工作流程。如果Google仅添加了这两项功能,我认为GPB可以说是“完整”的了,只需要一个相当于ASN.1的uPER就可以为那些存储空间或带宽很少的人完成。
请注意,其中很多都集中在项目的情况上,以及该技术的实际/快速/成熟程度。