移动端混合开发,常用数据结构传输能力对比分析

奇技指南

随着H5-Hybrid和Flutter开发热度的逐渐上升,各个VM之间的传输能力也是大家比较关心的问题之一。目前比较流行的传输结构有:Json,Protocol Buffers,Flat Buffers,本文对三种结构进行真机测试,通过实际数据来说明如何选择。

本文来自公众号花椒技术。

 

随着H5-Hybrid和Flutter开发热度的逐渐上升,各个VM之间的传输能力也是大家比较关心的问题之一。
目前比较流行的传输结构有:Json,Protocol Buffers,Flat Buffers,他们各自在Android/Flutter/H5传输的性能表现如何,对三种传输结构如何进行选择。本文对三种结构进行真机测试,通过实际数据来说明如何选择。

 

01、测试样本介绍

  • 测试样本选择:深度8层,150个字段组成,在日常业务中应该也是比较复杂的。

  • Json结构填充满数据大概是4KB的数据量

  • Protocol Buffers结构仅有2KB多点

  • Flat Buffers介于Protocol Buffers和Json之间。

 

 

02、Json、Protocol Buffers、Flat Buffers 结构分析

 

Json

1   "user":{"name":"mary"}"user":{"name":"mary"}

Json是一种K-V存储结构,在序列化和反序列化过程,会使用反射、遍历等方法,并且会产生一些临时对象,消耗一些内存,所以整体效率并不高效。
下面以Gson为例,简单分析一下反序列化过程:

  • 对传入Java Class进行处理,反射查找类Field,并创建对应的BoundField。并为Field的序列化和反序列化寻找合适的TypeAdapter。

  • 使用JsonReader对传入Json原始字符串进初步解析。

  • 对JsonReader进行遍历,根据JsonReader.nextName的type类型,获取对应的TypeAdapter对数据进行解析,并赋值给对应的Object Field。

 

Protocol Buffers

 
1message User {2    string name = 1;3}
2    string name = 1;
3}

Protocol Buffers结构是类似KV的一种结构体TLV。优点是体积小,为了缩小体积,Protocol Buffers会采用多种编码方式优化压缩比。序列化和反序列化速度较快。
Pb存储方式如下图所示:

640?wx_fmt=png

image

Protocol Buffers反序列化过程需要注意的是,反序列化过程与字段顺序无关,是通过TV结构来保障数据的准确性。
反序列过程中需要对整个数据流进行解码,生成可用Object或Map映射。

Flat Buffers

 

Flat Buffers 使用偏移量标记的流式存储结构。引用Facebook比较火的一张图:

640?wx_fmt=jpeg

image


从图中大概可以看出数据是如何存储的。
Flat Buffers支持多种嵌套结构:structs, tables, vectors。其中tables支持向前后兼容并且支持字段可选。其特性适用于大多业务需求,后续测试数据也是基于tables进行的。

Flat Buffers序列化会提前计算出内容偏移量,根据起始偏移量和内容数据长度等信息逐步存储。因需要存入一些偏移量长度等描述信息,所以体积上比Protocol Buffers要大一些。数据存储方式是采用Little Endian。

序列化的写法比较繁琐。在Java中使用如下:

 1// flat schema,table结构: 2table User { 3  name: string; 4  user: User; 5} 6// 数据填充 7FlatBufferBuilder builder = new FlatBufferBuilder(0); 8int name = builder.createString("mary"); 9User.startUser(builder);10User.addName(builder, name);11int endUser = User.endUser();12builder.finish(endUser);// flat schema,table结构:
 2table User {
 3  name: string;
 4  user: User;
 5}
 6// 数据填充
 7FlatBufferBuilder builder = new FlatBufferBuilder(0);
 8int name = builder.createString("mary");
 9User.startUser(builder);
10User.addName(builder, name);
11int endUser = User.endUser();
12builder.finish(endUser);

Flat Buffers反序列化过程:
首先看一下内存中的数据(十六进制表):

640?wx_fmt=png

image


每一个table结构都会包含两个比较重要的字段vtable_start和bb_ops。当Flat Object初始化时,在init方法中对ByteBuffer进行计算,获取对应table的vtable_start和bb_ops,为字段解析准备关键位信息。

真正访问table中的某个方法时,会对ByteBuffer进行动态解析。以name()方法说明,步骤如下:

 1  // api 2  public String name() { 3    int o = __offset(4);return o != 0 ? __string(o + bb_pos) : null; 4  } 5  // 获取o值 6  protected int __offset(int vtable_offset) { 7    return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0; 8  } 9  // 解析内容10  protected String __string(o+bb_ops) {11    offset += bb.getInt(offset);12    int length = bb.getInt(offset);13    return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length);14  }// api
 2  public String name() {
 3    int o = __offset(4);return o != 0 ? __string(o + bb_pos) : null;
 4  }
 5  // 获取o值
 6  protected int __offset(int vtable_offset) {
 7    return vtable_offset < vtable_size ? bb.getShort(vtable_start + vtable_offset) : 0;
 8  }
 9  // 解析内容
10  protected String __string(o+bb_ops) {
11    offset += bb.getInt(offset);
12    int length = bb.getInt(offset);
13    return utf8.decodeUtf8(bb, offset + SIZEOF_INT, length);
14  }

可以看出整个过程并没有涉及复杂的编解码和转换步骤。只是根据偏移量精准查找数据。所以解析速度非常高效。

 

03、传输通道分析

以上分析看来Flat Buffers和Protocol Buffers明显要优于Json。那么实际应用场景中又是如何?下面我们再看一下H5、Android、Flutter通道之间,在传输以上数据结构时,是怎么处理的。

 

常用的可选通道

首先介绍一下常用的可选通道:

  • Android和Flutter之间,目前还是通过Flutter官方提供的Channel通道来进行数据传输。

  • Android和H5之间,普遍做法是通过JsBridge,端上使用Webview.evaluateJavascript来调用H5,H5使用window.prompt调用端。现阶段Android端大部分使用的是Chrome的v8引擎。

  • Flutter和H5之间,是Flutter首先调用Android,再由Android调用H5。

 

android和flutter传输通道

640?wx_fmt=png

 

三种结构在传输过程中,由Java Object转变为Flutter Object都会经过两个步骤:

  • 首先进行序列化,生成Flutter通道所支持的数据类型String和Uint8List类型。

  • Flutter端接受数据后,采用各自的方式进行反序列化生成对应Object。

理论上体积越小,序列化和反序列化效率越高,传输性能就会越好。

android和H5传输通道

640?wx_fmt=png

 

从图中可以看出:
Protocol Buffers和Flat Buffers在传输中,会做一些额外的工作,需要把二进制流转化成JsBridge支持的传输类型。收到数据后,还需要对数据做解码工作。
而Json数据在Js Engine中是可以直接使用的。

对于Protocol Buffers和Flat Buffers有一点不能忽略:前面分析两者的编解码效率是比较高效的,并且体积上都要比Json小。这一点是不是可以弥补编解码带来的额外消耗,还需要通过实际测试来看一下。

 

04、测试结果

数据测试柱状图:

640?wx_fmt=png

 

通过柱状图结果很明显:

  • Android和Flutter 传输:Flat Buffers > Protocol Buffers > Json

  • Android/Flutter 和H5传输:Json > Flat Buffers/Protocol Buffers

测试说明:

  • 在和H5之间传输byte数组时,因需要进行base64编码,所以测试时间也包括整个base64的编解码消耗的时间。

  • 因Flutter目前提供的Channel通道是占用UI线程的,所以实际使用情况中,还需要考虑到这点。本测试暂不考虑UI卡顿问题。

  • 同一VM之间调用测试,因运行时的原因,有时候会有几千条甚至上万条的差异,但至少也能达到每秒几十万条的数据量,暂不考虑这种情况。

 

 

05、关于Flat Buffers

  • Flat Buffers传输测试的时候需要注意一点:接收到buffer数据后,需要对每一个字段进行字段解析,因Flat Buffers是流式结构,数据是根据字段偏移量动态获取,所以不能只转化成外层对象,需要对逐个字段进行解析,这样测试才比较合理,网上部分测试Flat Buffers结论比较夸张,大概也是这个原因。

    • 这两种情况分别测试了一下:不进行解析,也就是仅byte传输,大概能达到每秒30多万条。添加上字段解析,会下降到每秒1.1万条,还是比较明显的。

 

 

06、结 论 

  • 和H5之间进行数据传递时,因js的动态语言特性,和对Json结构的天然支持,应该优先考虑使用Json。

  • 和Flutter之间进行数据传递时,Flat Buffers,Protocol Buffers,Json要如何选择,还要看具体场景:

  • Json:使用便捷,成本很低,且易于维护和测试。但是相比其他两种结构,Json的自描述能力不足,在做跨语言沟通时候,仍旧需要依靠文档和主动沟通。并且在性能和安全性方面也存在缺陷。综合对比Json适合成本较小,业务数据多变的场景。

  • Protocol Buffers:目前比较主流的一种选择,工具链相对也比较全面。如果遇到传输性能瓶颈时,不妨考虑使用Protocol Buffers。Protocol Buffers的压缩比也是三种结构中最高的,并且在序列化和反序列化性能方面也比较突出。适合稳定或数据交互不频繁的场景。
    关于测试过程中可读性的问题,花椒团队做了对应的Web版本的抓包工具,从而解决了测试友好度的问题。

  • Flat Buffers:在序列化和反序列化方面有很大的优势。目前主要是Facebook和Cocos2d-x类应用在使用,比较适合游戏开发场景。缺点也很明显,体积上比Protocol Buffers要大一些。在数据创建时,比Protocol Buffers还要繁琐,后期维护也相对的麻烦一些。并且在不同平台上也有所差异化,考虑到国内应用的生态环境原因,所以很多时候也并非首选。

从业务前期来看Json是不错的选择。长远来看可以考虑使用Protocol Buffers。目前市面上的稳定业务也都趋向于用Protocol Buffers来替代Json。

 

 

其他测试数据

640?wx_fmt=png

 


测试设备是Android9.0系统。

 

 

参考文献

https://flutter.dev/docs/development/platform-integration/platform-channels
http://google.github.io/flatbuffers/flatbuffers_benchmarks.html
https://code.fb.com/android/improving-facebook-s-performance-on-android-with-flatbuffers/
https://developers.google.com/protocol-buffers/docs/proto3
https://www.ibm.com/developerworks/cn/linux/l-cn-gpb/

 

(360技术原创内容,转载请务必保留文末二维码,谢谢~)

在这里插入图片描述

关于360技术 360技术是360技术团队打造的技术分享公众号,每天推送技术干货内容
更多技术信息欢迎关注“360技术”微信公众号

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值