关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » 算法设计 »开源跨平台数据格式化框架概览

    开源跨平台数据格式化框架概览

    2015-01-14 00:00:00 出处:过往记忆的博客
    分享

    说到数据格式化框架,就不得不提到 Google 的 Protocol Buffers,Facebook 的 Thrift,还有 Apache Hadoop 推出的 Avro。Microsoft 最近开源的 Bond 也是一种用于数据格式化的可扩展框架,其适用的应用场景包括服务间通信、大数据存储和处理等。

    为什么会有这么多关于数据格式处理的框架?它们都在解决什么问题呢?我们先来观察一下典型的服务间通信的结构。

    通常,在设计服务间通信时,我们所要面对的基本问题有:

    如何传输数据? 使用什么协议通信? 数据以何种格式表达? 在服务端如何处理数据请求? 数据在服务端如何存储? 请求消息如何路由或转发?

    随着服务系统架构的不断演进,我们会面对更多的问题:

    适应架构演进的能力 适应集群扩展的能力 灵活性 延时 简单

    那么,以前我们都是在用什么技术来解决这些问题的呢?

    C 语言的动态结构体二进制传输 DCOM, COM+ CORBA SOAP XML, JSON

    都是听起来很熟悉的名字。实际上,C 结构体仍然被广泛地应用于网络底层通信,DCOM, CORBA, SOAP 正逐步退出历史舞台。目前,最流行的就是基于 XML 或 JSON 的序列化机制。

    但使用 XML 和 JSON 时也会面对一些问题:

    通信协议需要额外描述 需要维护服务端和客户端两侧契约代码 需要为设计的协议编写包装类 需要为不同编程语言编写实现 承担解析 XML 和 JSON 较高的开销 存储空间占用相对较多

    那么,对于这些数据处理和序列化框架,从软件设计人员的角度来看,我们最需要的到底是什么呢?

    多语言间的透明性 时间和空间效率 支持快速开发 能利用已有的类库

    所以,业界著名公司的开发人员分别推出了不同的框架,以期解决这些问题。包括 Google 的 Protocol Buffers,Facebook 的 Thrift,Apache Hadoop 的 Avro,和 Microsoft 的 Bond。

    Bond Protocol Buffers Thrift Avro
    框架起源 Microsoft Google Facebook Apache
    开源年份 2014 2008 2007 2009
    开源协议 MIT License BSD License Apache License 2.0 Apache License 2.0
    代码位置 GitHub GitHub Apache Apache
    官方文档 Documents Documents Documents Documents

    这些框架的一些共性:

    使用 IDL 定义,IDL (Interface Description Language) 性能较高 支持版本演进 采用二进制格式

    这些框架的典型使用过程:

    编写类似于结构体的消息格式定义,使用类似于 IDL 的语言定义。 使用代码生成工具,生成目标语言代码。 虽然生成了许多代码,但代码的可读性比较高。 在程序中直接使用这些代码。 生成的代码不允许编辑。

    也就是说,用户首先需要定义数据结构,然后生成可以有效读写这些数据结构的代码,再将代码嵌入到服务端与客户端的代码中使用。

    例如,下面使用 Protocol Buffers 的定义搜索请求消息 search.proto。

    package serializers.protobuf.test;
    
    message SearchRequest {
      required string query = 1;
      optional int32 page_number = 2;
      optional int32 result_per_page = 3 [default = 10];
      enum Corpus {
        UNIVERSAL = 0;
        WEB = 1;  }
      optional Corpus corpus = 4 [default = UNIVERSAL];
    }

    使用代码生成工具生成 C# 代码如下。

    namespace serializers.protobuf.test
    {
      [global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"SearchRequest")]
      public partial class SearchRequest : global::ProtoBuf.IExtensible
      {
        public SearchRequest() {}
    
        private string _query;
        [global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"query", DataFormat = global::ProtoBuf.DataFormat.Default)]
        public string query
        {
          get { return _query; }
          set { _query = value; }
        }
        private int _page_number = default(int);
        [global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"page_number", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        [global::System.ComponentModel.DefaultValue(default(int))]
        public int page_number
        {
          get { return _page_number; }
          set { _page_number = value; }
        }
        private int _result_per_page = (int)10;
        [global::ProtoBuf.ProtoMember(3, IsRequired = false, Name=@"result_per_page", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        [global::System.ComponentModel.DefaultValue((int)10)]
        public int result_per_page
        {
          get { return _result_per_page; }
          set { _result_per_page = value; }
        }
        private serializers.protobuf.test.SearchRequest.Corpus _corpus = serializers.protobuf.test.SearchRequest.Corpus.UNIVERSAL;
        [global::ProtoBuf.ProtoMember(4, IsRequired = false, Name=@"corpus", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
        [global::System.ComponentModel.DefaultValue(serializers.protobuf.test.SearchRequest.Corpus.UNIVERSAL)]
        public serializers.protobuf.test.SearchRequest.Corpus corpus
        {
          get { return _corpus; }
          set { _corpus = value; }
        }
        [global::ProtoBuf.ProtoContract(Name=@"Corpus")]
        public enum Corpus
        {            
          [global::ProtoBuf.ProtoEnum(Name=@"UNIVERSAL", Value=0)]
          UNIVERSAL = 0,
    
          [global::ProtoBuf.ProtoEnum(Name=@"WEB", Value=1)]
          WEB = 1,
        }
    
        private global::ProtoBuf.IExtension extensionObject;
        global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
          { return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
      }
    }

    IDL 语法

    使用 IDL 定义的语法通常包括:

    每个字段(Field)必须包含一个唯一的正整数标识符,例如 “= 1″, “= 2″ 或 “1 : “, “2 : ” 等。 字段可以被标记为 required 或 optional。 多个 structs 可以被定义在相同的文件中。 structs 可以包含其他 structs。 字段可以被指定默认值。

    这里,为字段指定的标识符 “= 1″, “= 2″ 或 “1 : “, “2 : ” 等称为 “Tag”,这个操作称为 “Tagging”。这些 Tag 用于从二进制的消息中识别字段,所以一旦定义并使用,则后续不能修改。

    Tag 的值在 1-15 区间时使用 1 byte 存储,在 16-2047 区间时使用 2 bytes 存储。所以,为节省空间,要将 1-15 留给最常使用的消息元素,并且要为未来可能出现的频繁使用元素留出空间。

    下面是各框架在 IDL 定义层的比较:

    Bond Protocol Buffers Thrift Avro
    File Extension .bond .proto .thrift .avpr
    Namespace namespace package namespace @namespace
    Import import “t.bond” import “t.proto” include “t.thrift” import protocol
    Compsite Type struct t {} message t {} struct t {} protocol t {}
    Tagging 1: int32 t; int32 t = 1; 1: i32 t ×
    Field Rules requiredoptional requiredoptionalrepeated requiredoptional -
    Base Types booluint8uint16

    uint32

    uint64

    float

    double

    string

    int8

    int16

    int32

    int64

    wstring

    doublefloatint32

    int64

    uint32

    uint64

    sint32

    sint64

    fixeD32

    fixed64

    sfixed32

    sfixed64

    bool

    string

    bytes

    boolbytei15

    i32

    i64

    double

    string

    nullboolean

    int

    long

    float

    double

    bytes

    string

     

    Containers listsetmap

    vector

    nullable

    blob

    × listsetmap

     

    recordarraymap

    union

    fixed

    Polymorphism √ × × ×
    Generics √ × × ×
    Enumerations enum t {} enum t {} enum t {} enum t {}
    Type Aliases using t = int64 × typedef i32 t @aliases
    Constants × × const i32 t = 1 ×
    Exceptions √ × exception t {} ×
    Services √ service t {} service t {} protocol t {}
    Attributes √ - - -
    Comments C++ Style C/C++ Style C/Shell Style Java Style

    注:”√” 代表支持,”×” 代表不支持,”-” 代表不涉及。

    编程语言支持

    各开源数据格式化框架默认会支持若干编程语言,一些没有被默认支持的编程语言通常在社区中也会找到支持。下面是各框架默认支持的开发语言:

    Bond Protocol Buffers Thrift Avro
    官方支持语言 C#, C++,Python C++, Java,Python C++, Java, Python,PHP, Ruby, Erlang,Perl, Haskell, C#,

    Cocoa, JavaScript,

    Node.js, Smalltalk,

    OCaml, Delphi

    C, C++, C#,Java, JavaScript,Python, Perl,

    PHP, Ruby

    开源语言实现 C#:protobuf-netprotobuf-csharp-port

    Node.js:

    node-protobuf

    性能比较

    以下性能比较数据来自 GitHub eishay/jvm-serializers 。

    Serializes only specific classes using code generation or other special knowledge about the class.

    create     ser   deser   total   size  +dfl
    kryo-opt                               64     658     864    1522    209   129
    wobly                                  43     886     536    1422    251   151
    wobly-compact                          43     903     569    1471    225   139
    protobuf                              130    1225     701    1926    239   149
    protostuff                             82     488     678    1166    239   150
    protobuf/protostuff                    83     598     692    1290    239   149
    thrift                                126    1796     795    2591    349   197
    thrift-compact                        126    1555     963    2518    240   148
    avro                                   89    1616    1415    3031    221   133
    json/json-lib-databind                 63   26330  103150  129479    485   263
    json/jsonij-jpath                      63   38015   12325   50339    478   259

    Total Time : Including creating an object, serializing and deserializing.

    Serialization Time : Serializing with a new object each time (object creation time included).

    Deserialization Time : Often the most expensive operation. To make a fair comparison, all fields of the deserialized instances are accessed – this forces lazy deserializers to really do their work.

    Serialization Size : May vary a lot depending on number of repetitions in lists, usage of number compacting in protobuf, strings vs numerics, assumptions that can be made about the object graph, and more.

    Object Creation Time : Object creation is not so meaningful since it takes in average 100 nano to create an object.

    版本演进

    各数据格式化框架通过 Tag 来支持版本控制,以支持前向和后向兼容。客户端与服务端的版本不匹配可归纳为 4 种情况:

    新增字段,旧 Client,新 Server; 新增字段,新 Client,旧 Server; 删除字段,旧 Client,新 Server; 删除字段,新 Client,旧 Server;

    正常情况:Client 和 Server 一致;

    Client 端和 Server 端消息定义字段一致。

    情况1:新增字段,旧 Client,新 Server;

    Client 端仍然使用旧版本。

    Server 端消息定义新增字段 branch_id。

    Server 端需要适配旧版本,也就是处理没有 branch_id 的消息。

    情况2:新增字段,新 Client,旧 Server;

    Client 端消息定义新增字段 branch_id。

    Server 端仍然使用旧版本。

    Server 端解析消息时实际上直接忽略了 branch_id 字段,所以不会产生问题。

    情况3:删除字段,旧 Client,新 Server;

    参考情况2。

    情况4:删除字段,新 Client,旧 Server;

    参考情况1。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。