V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chaleaoch
V2EX  ›  程序员

protobuf gRPC 这种写配置文件生成代码的形式 "流行"的原因是什么?

  •  1
     
  •   chaleaoch · 2021-06-12 00:01:15 +08:00 · 6627 次点击
    这是一个创建于 1262 天前的主题,其中的信息可能已经有所发展或是发生改变。
    再比如 mybatis 用 xml 写 sql.
    在比如 spring 初期用 xml 做 IOC...
    诸如此类. 这么做的目的是什么?

    作为一个 python 程序员不是很习惯.


    第二个问题是, 为什么讲 go 和 node 什么的 从 gRPC 里面扯出去新搞了一个仓库.
    类似的还有 protoc vs protobuf-gen-go


    谢谢大佬们.
    39 条回复    2021-08-11 18:05:28 +08:00
    Mitt
        1
    Mitt  
       2021-06-12 00:08:17 +08:00
    Protobuf 是二进制,并且在 protobuf 基础上还有各种 rpc 通讯等定义,protoc 和 protobuf-gen-go 分工不同,后者才是编译生成最终文件的,每个语言都有各自的 gen 工具
    abcysn
        2
    abcysn  
       2021-06-12 00:17:30 +08:00 via iPhone
    我 go 、c 、Python 都用,稍大点的工程还是偏好编译型的语言,也喜欢 protobuf 这种做法,感觉这样比较严谨,很多低级错误编译阶段就发现了,会省不少调试时间
    chaleaoch
        3
    chaleaoch  
    OP
       2021-06-12 00:21:16 +08:00
    @Mitt 谢谢,但是为什么分仓库呢... python 就没有分仓库啊.
    dcoder
        4
    dcoder  
       2021-06-12 00:23:48 +08:00
    protobuf 是跨语言的,所以搞成这样. 都是语言太多整出来的麻烦.
    你说的分库是 protobuf 各个语言生成器么? 多个库方便不同的 team 管理吧.
    chaleaoch
        5
    chaleaoch  
    OP
       2021-06-12 00:27:45 +08:00
    @Mitt 而且 protoc 安装一次就可以了 go 需要安装两个东西.
    chaleaoch
        6
    chaleaoch  
    OP
       2021-06-12 00:29:52 +08:00
    @dcoder 谢谢 就是说 从某种角度上来说将来各个语言都有可能单独拆出去.


    但是我不明白 gRPC-go 为什么要用 Go 重写一遍实现. 直接用 gRPC 不好吗? 这不是重复劳动吗?
    no1xsyzy
        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. ...
    CSM
        8
    CSM  
       2021-06-12 00:50:36 +08:00 via Android
    生成代码是因为目标语言不是动态语言,并且没有强大的宏系统
    agagega
        9
    agagega  
       2021-06-12 00:51:36 +08:00 via iPhone
    对于表达能力强的语言,完全可以用 DSL,而不是用这种生成器来搞一堆代码出来
    billlee
        10
    billlee  
       2021-06-12 01:23:32 +08:00
    时代的遗产吧,当时没有好用的编译期反射 /宏。

    ORM 方面,hibernate 就用 annotation processor. 序列化方面 java / golang 的 json 都用反射而不是代码生成了.

    Scala 甚至可以不写 proto 直接根据 case class 定义序列化成 protobuf
    jim9606
        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 也是有可能的。
    chinvo
        12
    chinvo  
       2021-06-12 04:13:01 +08:00 via iPhone
    protobuf .net 就不需要写 proto 文件, 可以直接定义 class 和 interface. 但是如果你要和其他语言通信, 你还是得用 proto 文件.
    wellsc
        13
    wellsc  
       2021-06-12 05:46:00 +08:00 via iPhone   ❤️ 3
    花里胡哨的,json +http 他不香吗
    suantong
        14
    suantong  
       2021-06-12 06:10:46 +08:00 via iPhone
    来源于游戏
    Leigg
        15
    Leigg  
       2021-06-12 08:59:33 +08:00
    因为是跨语言通讯数据格式,需要媒介连接,.proto 文件就是媒介
    horsley
        16
    horsley  
       2021-06-12 09:46:25 +08:00
    @chaleaoch 关键点在于你说的 直接用“grpc”,是说用 C++版本,而 Go 里面虽然是可以用 C++的库,但是会在编译上增加麻烦,并且影响构建二进制的平台兼容性。因此 Go 的习惯里面我们希望能用纯 Go 就纯 Go,系统库也是这么干的,例如说加解密相关的,很多程序都会依赖 openssl,而 Go 则不依赖 openssl 自行实现了
    LazyWolfLin
        17
    LazyWolfLin  
       2021-06-12 10:54:55 +08:00
    很多原因共同导致的。首先是前后端有跨语言的需求,当然跨语言格式有很多:xml 、 @wellsc 说的 json 、protobuf 。但是网络通道并不是一开始就是光纤和 4G 网,xml 、json 同 protobuf 在消息长度上有两倍甚至三倍的差距,这意味着使用 xml 和 json 会导致更大的网络延迟。
    LazyWolfLin
        18
    LazyWolfLin  
       2021-06-12 11:03:45 +08:00
    而 protobuf 相比于 xml 和 json 能够有更小的体积则是通过编码的方式达成的。为了保证同一份 proto 协议在前后端不同编码解码实现能够有一致表现,同时也为了减少程序员的编码负担,代码生成器 protoc 就必不可少了。
    bwangel
        19
    bwangel  
       2021-06-12 15:37:17 +08:00   ❤️ 3
    @wellsc json 真的一点都不香。

    前端要什么,后端就返回什么,一个字段不许少,一个字段不许多。

    “一个字段不许多”。这一点很多接口都做不到。
    wellsc
        20
    wellsc  
       2021-06-12 16:30:33 +08:00
    @bwangel 这。。。不是框架自己做的限制?
    12101111
        21
    12101111  
       2021-06-12 16:31:28 +08:00
    @bwangel 一个字段不许少,一个字段不许多是你选的 json 解析器的问题, 我用 rust 的 serde 就没有这么多麻烦, 结构体上面加几个属性就完事了
    uselessVisitor
        22
    uselessVisitor  
       2021-06-12 17:17:18 +08:00
    历史原因
    luozic
        23
    luozic  
       2021-06-12 17:47:01 +08:00
    网络和 cpu 都是比较昂贵的资源,计算机上为了节约资源,各种骚操作多得是。 了解一下,字符集编码
    paoqi2048
        24
    paoqi2048  
       2021-06-12 20:07:38 +08:00
    其实这个在游戏领域还挺普遍的
    bwangel
        25
    bwangel  
       2021-06-12 22:00:21 +08:00   ❤️ 1
    @12101111

    这不是语言的问题,这是程序的设计问题。前端版本由 V1 升级成了 V2,它们说不用 A,B,C 三个字段,这时候更新文档,告知后端,这是不可靠的,没准后端忙就忘了,反正也不会出错。如果前后端共用一份 protobuf 文件,那么就会强制后端更新接口,如果不更新会出错。

    另外顺口问一句,哪家公司的 web 接口是用 rust 写的,让我膜拜一下。或者不一定是公司,哪个网站是用 rust 写的,让我膜拜膜拜。
    bwangel
        26
    bwangel  
       2021-06-12 22:04:38 +08:00   ❤️ 1
    @wellsc

    这不仅仅是后端的事情,而是前后端要共同维护一份协议,告知双方现在在用哪些字段。维护一份 proto 文件,比维护一个 Markdown 文件要可靠的多。
    bwangel
        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 是最好的选择。
    wellsc
        28
    wellsc  
       2021-06-12 22:36:29 +08:00 via iPhone
    @bwangel 这……贵司还在用 markdown 维护接口文档?
    Evilk
        29
    Evilk  
       2021-06-12 22:48:36 +08:00 via iPhone
    json+http
    走遍天下
    bwangel
        30
    bwangel  
       2021-06-12 23:01:07 +08:00
    @wellsc

    额,是的,有什么更好的方案可以推荐一下吗?我用过 swagger,但它没办法要求客户端,感觉是一个交互式的 Markdown 。
    jim9606
        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 的功能。
    dayeye2006199
        32
    dayeye2006199  
       2021-06-13 02:54:41 +08:00
    面向协议编程的胜利。
    凡是接口文档另外开 markdown 靠人来写作的,基本都不怎么靠谱。
    主要靠良好的接口声明+代码内注释,自动生成接口文档。
    dcoder
        33
    dcoder  
       2021-06-13 04:48:21 +08:00
    @jim9606
    JSON schema 的思想是好,但是实现略复杂,用起来感觉重
    要是有个简化版的 JSON schema + 统一标准的各语言实现就好了
    wweir
        34
    wweir  
       2021-06-13 10:22:58 +08:00
    我理解很重要的一个原因是标准化:
    平时合作过程中不得不面对各种接口对接的事情,很多人习惯不同,更有很多人自创一些奇奇怪怪的标准。这时使用 GRPC 这个事实标准会省事很多,避免了很多对接的麻烦。
    更爽的是,用 GRPC 可以避免流控、追踪等一大堆通用型、难度都很高的事情,专注于自己的业务
    iyaozhen
        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 的代码框架都生成了。类似于脚手架
    evilStart
        36
    evilStart  
       2021-06-14 22:26:48 +08:00 via Android
    @bwangel openapi
    evilStart
        37
    evilStart  
       2021-06-14 22:30:43 +08:00 via Android
    @bwangel openapi 比 markdown 好多了吧。不光是一个接口文档,各语言和框架应该都有支持通过 Open API 生成接口、validation 甚至 stub 的工具。更新一份文档各端都能保证同步啊。
    Joway
        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 其实就是想要用一个语言实现走天下)。
    henryhu
        39
    henryhu  
       2021-08-11 18:05:28 +08:00
    我们刚使用上 pb, 有下面两点(亮点),真香:
    1. 体积小,而且系列化 /反系列化结构化数据速度快。我们处理 3D 模型, 模型文件通常体积大,处理相当耗时,所以这个功能对我们来说是刚需。
    2. 跨语言。我们要在多个平台共享数据,涉及 JS,c#,Ruby 。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3245 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 13:11 · PVG 21:11 · LAX 05:11 · JFK 08:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.