1
Mitt 2021-06-12 00:08:17 +08:00
Protobuf 是二进制,并且在 protobuf 基础上还有各种 rpc 通讯等定义,protoc 和 protobuf-gen-go 分工不同,后者才是编译生成最终文件的,每个语言都有各自的 gen 工具
|
2
abcysn 2021-06-12 00:17:30 +08:00 via iPhone
我 go 、c 、Python 都用,稍大点的工程还是偏好编译型的语言,也喜欢 protobuf 这种做法,感觉这样比较严谨,很多低级错误编译阶段就发现了,会省不少调试时间
|
4
dcoder 2021-06-12 00:23:48 +08:00
protobuf 是跨语言的,所以搞成这样. 都是语言太多整出来的麻烦.
你说的分库是 protobuf 各个语言生成器么? 多个库方便不同的 team 管理吧. |
6
chaleaoch OP |
7
no1xsyzy 2021-06-12 00:46:27 +08:00
@chaleaoch 重复造轮子是程序员常态
http://paulgraham.com/own.html ... It's easy for something new to feel like a project of your own. That's one of the reasons for the tendency programmers have to rewrite things that don't need rewriting, and to write their own versions of things that already exist. ... |
8
CSM 2021-06-12 00:50:36 +08:00 via Android
生成代码是因为目标语言不是动态语言,并且没有强大的宏系统
|
9
agagega 2021-06-12 00:51:36 +08:00 via iPhone
对于表达能力强的语言,完全可以用 DSL,而不是用这种生成器来搞一堆代码出来
|
10
billlee 2021-06-12 01:23:32 +08:00
时代的遗产吧,当时没有好用的编译期反射 /宏。
ORM 方面,hibernate 就用 annotation processor. 序列化方面 java / golang 的 json 都用反射而不是代码生成了. Scala 甚至可以不写 proto 直接根据 case class 定义序列化成 protobuf |
11
jim9606 2021-06-12 02:58:36 +08:00 2
第一个问题:这些场景的 xml 其实是当成 DSL 用的。因为当时的环境直接用编程语言表达这个很不直观。
考虑下用执行代码描述一个用户界面,你得用这种顺序描述: A.init,A.setP1,A.setP2,B.init,B.setP1,C.init,B.addChild(C),A.addChild(B) 如果换成 xml 能更好地体现层次结构,更好维护。 第二个问题:protoc 项目支持(proto->C/C++/OC/C#/Py/Ruby/java),protobuf-gen-go 项目支持(proto->go),项目本身用啥语言跟支持输出啥代码没有必然联系,你要愿意的话在 protoc 上扩充一下实现输出 go 也是有可能的。 |
12
chinvo 2021-06-12 04:13:01 +08:00 via iPhone
protobuf .net 就不需要写 proto 文件, 可以直接定义 class 和 interface. 但是如果你要和其他语言通信, 你还是得用 proto 文件.
|
13
wellsc 2021-06-12 05:46:00 +08:00 via iPhone 3
花里胡哨的,json +http 他不香吗
|
14
suantong 2021-06-12 06:10:46 +08:00 via iPhone
来源于游戏
|
15
Leigg 2021-06-12 08:59:33 +08:00
因为是跨语言通讯数据格式,需要媒介连接,.proto 文件就是媒介
|
16
horsley 2021-06-12 09:46:25 +08:00
@chaleaoch 关键点在于你说的 直接用“grpc”,是说用 C++版本,而 Go 里面虽然是可以用 C++的库,但是会在编译上增加麻烦,并且影响构建二进制的平台兼容性。因此 Go 的习惯里面我们希望能用纯 Go 就纯 Go,系统库也是这么干的,例如说加解密相关的,很多程序都会依赖 openssl,而 Go 则不依赖 openssl 自行实现了
|
17
LazyWolfLin 2021-06-12 10:54:55 +08:00
很多原因共同导致的。首先是前后端有跨语言的需求,当然跨语言格式有很多:xml 、 @wellsc 说的 json 、protobuf 。但是网络通道并不是一开始就是光纤和 4G 网,xml 、json 同 protobuf 在消息长度上有两倍甚至三倍的差距,这意味着使用 xml 和 json 会导致更大的网络延迟。
|
18
LazyWolfLin 2021-06-12 11:03:45 +08:00
而 protobuf 相比于 xml 和 json 能够有更小的体积则是通过编码的方式达成的。为了保证同一份 proto 协议在前后端不同编码解码实现能够有一致表现,同时也为了减少程序员的编码负担,代码生成器 protoc 就必不可少了。
|
19
bwangel 2021-06-12 15:37:17 +08:00 3
|
21
12101111 2021-06-12 16:31:28 +08:00
@bwangel 一个字段不许少,一个字段不许多是你选的 json 解析器的问题, 我用 rust 的 serde 就没有这么多麻烦, 结构体上面加几个属性就完事了
|
22
uselessVisitor 2021-06-12 17:17:18 +08:00
历史原因
|
23
luozic 2021-06-12 17:47:01 +08:00
网络和 cpu 都是比较昂贵的资源,计算机上为了节约资源,各种骚操作多得是。 了解一下,字符集编码
|
24
paoqi2048 2021-06-12 20:07:38 +08:00
其实这个在游戏领域还挺普遍的
|
25
bwangel 2021-06-12 22:00:21 +08:00 1
@12101111
这不是语言的问题,这是程序的设计问题。前端版本由 V1 升级成了 V2,它们说不用 A,B,C 三个字段,这时候更新文档,告知后端,这是不可靠的,没准后端忙就忘了,反正也不会出错。如果前后端共用一份 protobuf 文件,那么就会强制后端更新接口,如果不更新会出错。 另外顺口问一句,哪家公司的 web 接口是用 rust 写的,让我膜拜一下。或者不一定是公司,哪个网站是用 rust 写的,让我膜拜膜拜。 |
26
bwangel 2021-06-12 22:04:38 +08:00 1
|
27
bwangel 2021-06-12 22:20:19 +08:00 2
很多回复里都说 protobuf 的优势是编译后数据体积小。但我觉得这不是一个主要的优点,文本内容的压缩率很高的,Nginx 开启 gzip 压缩后,json 响应并不一定比 protobuf 响应要大很多。
我觉得主要优点就是强制性,定好一个规范后,通信的双方必须完全遵守它。 JSON 也可以做到这一点,但没有跨语言的解决方案,例如 21 楼老哥说的 rust 的 serde 就可以做到,但它不能跨语言,前后端无法使用同一份约束文件,那维护协议还是得靠 Markdown,还是不靠谱。 支持这几种主流语言( Java,PHP,Python,JS,Object-C,Swift,C++, Go )的数据序列化解决方案中,protobuf 是最好的选择。 |
29
Evilk 2021-06-12 22:48:36 +08:00 via iPhone
json+http
走遍天下 |
30
bwangel 2021-06-12 23:01:07 +08:00
|
31
jim9606 2021-06-12 23:44:59 +08:00 2
@bwangel JSON 想做到这点的可以用 JSON schema,前后端都老实点在 encode/decode 时用 schema validator 验证一遍。
( https://json-schema.org/implementations.html ) 自描述的数据格式理论上都可以用 schema 验证,protobuf 由于不是自描述结构,所以等于强制所有程序实现了 schema 的功能。 |
32
dayeye2006199 2021-06-13 02:54:41 +08:00
面向协议编程的胜利。
凡是接口文档另外开 markdown 靠人来写作的,基本都不怎么靠谱。 主要靠良好的接口声明+代码内注释,自动生成接口文档。 |
33
dcoder 2021-06-13 04:48:21 +08:00
|
34
wweir 2021-06-13 10:22:58 +08:00
我理解很重要的一个原因是标准化:
平时合作过程中不得不面对各种接口对接的事情,很多人习惯不同,更有很多人自创一些奇奇怪怪的标准。这时使用 GRPC 这个事实标准会省事很多,避免了很多对接的麻烦。 更爽的是,用 GRPC 可以避免流控、追踪等一大堆通用型、难度都很高的事情,专注于自己的业务 |
35
iyaozhen 2021-06-13 13:08:29 +08:00
可能楼主主要是相对比较 json+http 吧
其实 protobuf 也可以和 http 配合,我们几乎都这样。 protobuf 主要是对标 json 。 1. 协议字段严格约束,比如一个 list,如果没有应该返回 [],但被调方有可能返回 false 。轻则调用失败,重则客户端 crash 。不要觉得这个很低级,我已经见过很多次了。 2. protobuf 解析的更快,这个就要从 socket 编程说起,那时候都是定义一个 c 结构体,传输数据,其它语言按 c 的实现。但有个问题,没有中间 IDL 文件,别的语言都是对着着.c 文件自己实现,用现在的话说就是会被 C 掐脖子,实现个新功能还得看 c 支不支持。随着 web 2.0 c 也没落了。有些同学可能了解,中间出现过 msgpack 用的人也很多。但 pb 的爹好呀。 看 https://msgpack.org/ 就知道为什么二进制打包的格式更好了。 3. pb 更近一步的是 gRPC 生态繁荣,虽然大公司都是自研的 rpc 框架,但肯定得对标 gRPC,就很自然的选择了 pb 这里的流行更多的是随着微服务的发展,rpc 更加的流行带来的。为了效率就必然有很多工具生成代码。 protoc 只是把发起一个请求的 request/response 的数据结构生成了,方便.set 各种方式赋值,组成请求。但 protobuf-gen-go 更进一步是吧 client 和 server 的代码框架都生成了。类似于脚手架 |
37
evilStart 2021-06-14 22:30:43 +08:00 via Android
@bwangel openapi 比 markdown 好多了吧。不光是一个接口文档,各语言和框架应该都有支持通过 Open API 生成接口、validation 甚至 stub 的工具。更新一份文档各端都能保证同步啊。
|
38
Joway 2021-06-15 10:57:47 +08:00 1
这是一个很长的问题,前面有些人说的 json+http 走遍天下,首先对计算机历史而言,json 是一个很新的技术,以前的人就没这玩意可用。再者,很多时候 json 走不遍天下。如果你们公司有 10 种编程语言,用 json 你需要人肉维护 10 种 json 的 struct,如果有类型变化或者字段新增,也需要人肉去维护这个变更,这在大规模 RPC 服务场景下是不太可能的。何况有些字段是 required,靠人力手动在 10 种编程语言里实现这个约束是不现实的。而这个仅仅是序列化层面的事情,
我建议把这几个问题串起来看 RPC 在这几十年中的演变会更加明白其中的意义,最新在写一个 RPC 系列: https://blog.joway.io/tags/rpc/ ,可以看看序列化和连接这部分,就能够明白为什么 RPC 是一个语言强相关的活,很难用一个语言 implement 走遍天下(现在的 Service Mesh 其实就是想要用一个语言实现走天下)。 |
39
henryhu 2021-08-11 18:05:28 +08:00
我们刚使用上 pb, 有下面两点(亮点),真香:
1. 体积小,而且系列化 /反系列化结构化数据速度快。我们处理 3D 模型, 模型文件通常体积大,处理相当耗时,所以这个功能对我们来说是刚需。 2. 跨语言。我们要在多个平台共享数据,涉及 JS,c#,Ruby 。 |