首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【附近的人】序列化之白送篇---msgpack大战protobuf

【附近的人】序列化之白送篇---msgpack大战protobuf

作者头像
老李秀
发布2019-11-12 17:40:29
4.3K0
发布2019-11-12 17:40:29
举报

本文没有什么亮点不高端不涉及高性能高并发而且网上一搜一大把发誓文章没有蹭mp和pb热点最后的末尾有会挂一个微信的广告

  • 本文可能会存在错误欢迎公号留言指出或者公正讨论

常见的序列化/反序列化四大小王子:

  • thrift
  • msgpack
  • protobuf
  • json

第一个和第四个就不说了昂,然后是各种语言内置的序列化与反序列化函数也不说了昂。一般说来说各种各样的语言都有着自己各种花式数据结构和对象,但各种语言之间的这些数据结构和对象都是彼此不开眼的。比如Golang的struct和PHP的object,不开眼;Java的map和Python的dict,不开眼。如果说这几种语言之间想小刀剌屁股---开开眼,那么最初的方案可能是xml,然后再后来成了json...

所以序列化和反序列化要解决的问题就是:

  • 将不同语言的特有数据结构搞成大家都认的二进制串子
  • 将大家都认的二进制串子搞成不同语言的特有数据结构

说到这里应该get到点了,如果在一大坨微服务构成的庞大业务系统中,各个业务系统之间飞数据的序列化反序列化部分需要技术选型时候,参考标准是什么?

  • 性能?序列化和反序列化的速度越快越好,序列化后的数据占用空间越小越好,你觉得有没有道理?
  • 可读性?可读性最好的应该是json咯?这里主要说的是序列化完毕后你肉眼看到的是一坨什么玩意,如果一眼就能看到序列化后那坨玩意是啥样想必会好很多,你觉得合情不?
  • 扩展兼容?如果业务频繁改动,添加新字段还要兼容原来业务,对扩展性和兼容性就应该有讲究了,你觉得合理不?
  • 健壮性和通用性?主要是通用性吧,要知道如果这个序列化反序列化方案属于某个平台语言专有,那还是很难受的。一个成熟完整的方案一定能够兼顾众多语言众多特性,比如说thrift吧假如TA不支持Java的map或者对php的array支持不好,就有点儿扯了,你觉得在理不?

然而其实大家还是只看中第一条

我要开始表演了,你们准备好复制粘贴了吗?


msgpack

这玩意的官网是https://msgpack.org/,打开你应该能发现一大坨各种各样包括你没见过的语言对msgpack的实现,比如Golang比如PHP比如C,下面看下PHP和Golang的case吧。

先说PHP的,PHP对msgpack的实现最好用鸟哥实现的那个msgpack扩展,使用起来非常非常非常粗暴简单,并同时与JSON简单对比一下,你们感受下:

<?php$user = array('id'       => mt_rand( 10000000, 9999999999 ),'username' => 'etc'.time(),'password' => md5( time() ),'avatar'   => 'http://cdn.qiniu.com/user/big-avatar-png.png','age'      => 12,'gender'   => 'male','remark'   => array(array('id'     => 1,'title'  => '从呢结果 i 难过我的卡带','remark' => '空间看撒附近卡积分阿空间和饭卡金额为阿看到肌肤垃圾发酵了房间',    ),array('id'     => 1,'title'  => '从呢结果 i 难过我的卡带','remark' => '空间看撒附近卡积分阿空间和饭卡金额为阿看到肌肤垃圾发酵了房间',    ),array('id'     => 1,'title'  => '从呢结果 i 难过我的卡带','remark' => '空间看撒附近卡积分阿空间和饭卡金额为阿看到肌肤垃圾发酵了房间',    ),  ),);$counter = 900000;$begin   = microtime( true );for( $i = 1; $i <= $counter; $i++ ) {  $msg  = msgpack_pack( $user );  $data = msgpack_unpack( $msg );}$end = microtime( true );echo "msg序列化和反序列化{$counter}次:".( $end - $begin ).PHP_EOL;
$begin = microtime( true );for( $i = 1; $i <= $counter; $i++ ) {  $msg  = json_encode( $user );  $data = json_decode( $msg, true );}$end = microtime( true );echo "json序列化和反序列化{$counter}次:".( $end - $begin ).PHP_EOL;

msgpack的PHP API一共就两个函数:msg_pack和msg_unpack,用起来非常粗暴,执行下刚才的php文件看下结果:

下面看下Golang的msgpack的demo,感受下:

package mainimport ("fmt""time""github.com/shamaton/msgpack")type AvatarItem struct {  Id  int  Url string}type User struct {  Id       int  Username string  Password string  Age      int  Gender   string  Avatar   []AvatarItem}func main() {  avatar := AvatarItem{    Id:12,    Url:"http://cdn.qiniu.com/avatar.png",  }  user := User{    Id:123,    Username:"xiaodushe",    Password:"3fjkwejk3jb3h",    Age:44,    Gender:"male",    Avatar:[]AvatarItem{      avatar,      avatar,      avatar,    },  }  begin := time.Now().UnixNano()for i := 1; i <= 900000; i++ {    encodeUser, err := msgpack.Encode( user )if err != nil {panic( err )    }    user   = User{}    err    = msgpack.Decode( encodeUser, &user )  }  end := time.Now().UnixNano()  ret := end - begin  fmt.Println( "msgpack序列化反序列化900000次:", ret )}

注意这里用的时间单位是UnixNano,你们感受下:


protobuf

相对msgpack而言,protobuf可能稍微麻烦些,protobuf有一个类似于thrift idl的流程,就是需要先定义好数据结构,对于广大php而言,这么做似乎又有一个好处:莫名其妙数据结构变化或者数据类型发生变化。

首先你得安装好proto-compiler(类比thrift-compiler),这个八仙过海哈,八仙过海~这还还不够,你还需要golang proto插件(注意与proto-compiler是两回事),命令如下:

go get github.com/golang/protobuf/protoc-gen-go

其次是再安装好protobof FOR golang的库文件,注意这和上面protoc-compiler和protoc-gen-go插件又是两码子事儿:

go get github.com/golang/protobuf/proto

然手定义好数据结构,也就是一个proto文件,比如下面这个(先说了昂,这里就不普及proto文件的语法了):

syntax = "proto2";package protopack;enum FOO{X = 0;};message User{required string message = 1;required int32  length  = 2;required int32  cnt     = 3;}

最后,使用protoc-compiler生成一下相关文件:

protoc --go_out=./protopack *.proto

然后在你golang的工作目录下的protopack文件夹(自己手工建一个protopack)中生成一个go文件,这个文件就是存放数据结构的地方,截个图你们感受下:

测试用的golang demo代码如下:

package mainimport ("fmt""protopack""github.com/golang/protobuf/proto")func main() {  message := "xiaodushe"var length int32 = 12var cnt    int32 = 34  ret := &protopack.User{    Message: &message,    Length : &length,    Cnt    : &cnt,  }  // protobuf encode 序列化  encodeData, err := proto.Marshal( ret )if err != nil {panic( err )  }  fmt.Println( encodeData )// protobuf decode 反序列化  decodeData := &protopack.User{}  err = proto.Unmarshal( encodeData, decodeData )if err != nil {panic( err )  }  fmt.Println( decodeData )}

go run下?

估计会有老铁好奇,为什么不顺带做个语言之间的评测比赛啥的,这个咳咳,根据我的一贯经验,能引起争论的东西最好不要发也不要说,大部分人是理性的可以好好说话,但总有你惹不起的人,所以想做个test的诸位自己跑一下?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能API社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档