Json VS Protobuf

2015-04-27 02:10:57 +08:00
 yueyoum
https://github.com/yueyoum/playground/tree/master/Json%20VS%20Protobuf

周末两天都在搞这个东西,
手里几个项目都用的 protobuf,最初是觉得方便,
最近觉得 json其实比 protobuf还方便,特别是在服务端。

于是自己就对 json 和 protobuf 在打包大小,速度方面做了测试。
特别加入了C#,因为客户端用的这个。

从客户端来看, protobuf 还是占有很大优势的。
13602 次点击
所在节点    程序员
43 条回复
yueyoum
2015-04-27 12:46:01 +08:00
@est

感谢推荐 ,不过非主流格式 是从来就不会考虑的。
毕竟 是要在不同语言之间 交换数据的。 所以还是得用 通用点的
alpha1130
2015-04-27 13:15:29 +08:00
json在后期大规模使用的时候,如果文档不完善或者相关接口资料更新不及时,绝对是个灾难
HeyMan
2015-04-27 13:17:06 +08:00
感觉 http 接口还是用 json 好一点,可读性强,也方便扩展,pb两端都要重新编译。内部模块传输的话 pb 体积小,性能好。
dcoder
2015-04-27 13:23:09 +08:00
@alpha1130 你说的这个问题, 如果规划不档, 或者 msg 校验不严格, 任何 msg 格式都有这问题

推荐 lz 看看 JSON schema, 可以做跨语言的 JSON msg 严格校验
http://json-schema.org/examples.html
http://json-schema.org/implementations.html
VYSE
2015-04-27 13:55:45 +08:00
@yueyoum msgpack优势在size和speed,我们序列化数据存储和计算模块优先选择了它
yueyoum
2015-04-27 13:57:38 +08:00
@dcoder

我倒不知道有个 json-schema 来规定这种事情

不过我以前自己想过类似的实现:

{
"version": xxx,
"fields": ["a", "b"],
"a": xxx,
"b": xxx
}


带有 version, 这样在一定程度上做到 不同版本兼容
fiels, 就是来说明这个 json 有那些 key 是带着数据的


就如同你说的, 规划好了, 其他方式也能做到这样
neoblackcap
2015-04-27 18:04:04 +08:00
Apache Thrift呢?
yueyoum
2015-04-27 18:40:57 +08:00
@neoblackcap

以前看过,觉得有点复杂, 就没再研究了
alpha1130
2015-04-27 18:50:29 +08:00
alpha1130
2015-04-27 18:52:05 +08:00
@dcoder
json存在这个问题,不过像protobuf, thrift不会有那么大的问题
XadillaX
2015-04-27 18:54:47 +08:00
我说 NBT 你会不会打我?

https://github.com/XadillaX/mcnbt

只是开个玩笑 2333333。
reorx
2015-04-27 22:02:52 +08:00
@alpha1130 赞同,Protobuf 相比 JSON 的优势在于它本身带有严格的 schema validation,一份 .proto 文件既作为 input/output 的入口,又作为规定数据格式的文档,在跨语言多人协作的项目上用起来不能更爽。实际上我觉得 Protobuf 和 JSON 是完全不同的两种东西,Protobuf 是 schema + data format,schema 是我们可以看见的 proto 文件里的定义,data format 是它序列化成二进制数据的格式,JSON 只有 data format…至于 JSON schema,个人觉得是一种很勉强的实现,在本身没有 schema 的数据格式上做 schema 的事情,无论是写起来还是用起来都很麻烦,说到底,JSON 只是一种轻量的、面向 Web 的 data format 罢了。
hiboshi
2015-04-27 22:49:09 +08:00
protobuf在Google大规模的使用 是最好的例子
dcoder
2015-04-28 02:15:06 +08:00
@alpha1130
@reorx
很好的讨论, 看完对 Protobuf 更感兴趣了

不过我再提个问题, 如果后端 service 多用 JSON 存储, 比如各种 NoSQL database 都流行存 JSON. 不只是 MongoDB, 还有很多重量级的产品都是直接用 JSON 来描述数据的, 严格与否只是 JSON format 制定者的严谨程度决定的. 比如 DynamoDB, ElasticSearch.

这样的话, 用 Protobuf 的数据还是得再做一次到 JSON 的转化.
我设计时候, 喜欢 Layers 尽量少, 一堆 Layer 和 data format 之间转换, 我觉得设计比较笨重.
比如我存 JSON-based log 到 MongoDB/DynamoDB/ElasticSearch 的话, 直接用 JSON 是非常方便和简洁的设计.
dcoder
2015-04-28 02:33:07 +08:00
@yueyoum
还有, 一般的 JSON on Mono 库在 iOS 上是有 AOT 坑的, 所以我才专门推荐了一个 JSON .NET 库.
同理, 你可以 Google 一下 protobuf-net Unity/Mono AOT 这些关键词组合, 应该也是有坑的.
yueyoum
2015-04-28 10:19:57 +08:00
@dcoder
protobuf-net 在IOS确实有 AOT的问题, 我在 github中的说明里 特别提过了,以及解决办法。

估计是 那篇说明太长, 大部分都没仔细看。

就像上面还有些同学总说 web 什么的, 显然我不是做web的啊。


关于 Layers, 我的感觉是 Layers 肯定是不会少的,

毕竟你不会直接把数据库中的数据返回给客户端,也不会直接把客户端发来的数据存入数据库。
肯定要加

一层数据校验 用于接收客户端消息
一层数据打包 用于给客户端发送消息
一层事件发送 (可选),用于hook,或者统计

你的意思应该是 这么多层 你都想用同样的方式, 比如json, 而不想各种格式都有 对吧?



还有 其实说的那些 JSON SCHEMA 格式校验,
我觉得根本没必要。

无论是客户端还是服务器, 对于接收到的消息, 按照 预设的方式去解析, 如果解析出错
直接报 消息格式 错误就行。
dcoder
2015-04-28 12:01:41 +08:00
@yueyoum
是的, 只是在 JSON 这一个通用格式上做各种逻辑, 这种统一格式的设计会非常简洁
JSON SCHEMA 是说基本的 filed 校验逻辑不用再写了, 因为在不同语言中再写一遍还是挺麻烦

另外, 抱歉我没看到你处理 protobuf-net AOT 的方法, 能麻烦你贴一下链接么, 学习一下 :)
reorx
2015-04-28 12:09:44 +08:00
@dcoder 其实 JSON 和 Protobuf 我都很喜欢,两者都有自己的优点,根据场景恰当地挑选要使用的技术就好了。

我觉得 JSON 使用的场景一般是,不太需要考虑内部协定的 schema,或者说多个服务之间使用的数据格式并不强要求是一致的。比如一个 Web 后端 A,内部依赖服务 B,A 暴露给客户端的接口是 RESTful 的 JSON API,A 调用 B 时通过 B 提供的 RPC library,整个服务场景中存在两种接口和数据格式,互相没有什么关联,也不要求一致,这时用 JSON 就很好(原本 JSON 就是所有数据格式中最 human readable 的),每个服务自己维护自己的解析和参数验证。

Protobuf 一般是涉及到多个服务之间的数据交换,且每个服务内部用的数据要求用一致的 schema,这种大部分都不是 Web 项目,一般都是用网络编程框架做的传统后端,非常依赖 RPC 调用的服务。这时用 Protobuf 或者 Thrift 就非常好了,因为其实 Protobuf、Thrift 都是提供了一种序列化结构数据的方法,然后提供了一种用于描述结构数据的语法规则,在这个基础上其实已经把 data format 给抽象不见了,我们不需要知道它底下序列化后的二进制数据长什么样子,我们只关心每个使用同一份 proto 定义的服务内部的数据都是对应一致的 schema,且可以无缝转移到另一个服务中使用(这个过程我们也不需要关心)。如果我选择 Protobuf 而非 JSON,必然是因为它在打通跨服务的数据一致性上的优点,而不是它相比 JSON 性能有何优势。

当然最终选择的时候还有个很关键的因素,就是整个大环境的技术选型,如果你所依赖的其他组件用 JSON 的较多,那么也不要刻意用 Protobuf 搞得大家都很麻烦。如果一个大型项目在一开始就用了 Protobuf 作为数据格式的约定,后期在数据一致性上可能出现很多麻烦就可以避免掉呢。

最后说点我使用 Protobuf 的经验,项目里的每个 proto 文件都会在最上面标注一个 version number,所有的 required 字段一经定下允许再更改,对 proto 文件的提交必须保证严格的 review,不能随便 merge 到 master,如果被多个项目需要甚至会把 proto 文件单独放到一个 git repo 里,在其他需要它的地方用 git submodule 引用。

P.S. 写完发现用了好多个「一致」,有点啰嗦,赶吃饭就先这样了…
reorx
2015-04-28 12:11:04 +08:00
「所有的 required 字段一经定下允许再更改」→「所有的 required 字段一经定下 **不允许** 再更改」orz
yueyoum
2015-04-28 12:51:28 +08:00
@dcoder

用 precompile 来应对 IOS 的 AOT 问题
我是参考的这个帖子: http://game.ceeger.com/forum/read.php?tid=13479

我直接写一个 命令行工具来做这些事情: https://github.com/yueyoum/pg

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/186561

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX