求教各位后端大佬,用 gRPC 来实现 TS 与 Python 服务之间的通信时遇到了问题

188 天前
 superhot

目的

实现后端微服务架构中 TS 与 Python 服务之间的通信,希望能通过维护同一套类型定义/ Schema 保证 single source of truth ,提高接口可维护性。

尝试过的方案

  1. 最简单的方案,Python 服务用 Flask 实现普通的 REST API 来对其他模块提供服务。问题是一方接口定义更改时,另一方需要同步更改,如果是纯 TS 项目的话,得益于类型信息共享,先改类型定义,所有受影响的地方都能及时发现,后改相关代码就很方便,也比较安心,但如果是多语言的话做不到这点
  2. 借此机会想试试 RPC 替代 REST ,于是尝试了一下 gRPC ,本身多语言支持,还有通用统一的 Protobuf ,看上去很美好,然而可能是我太菜不熟悉,感觉这玩意用起来槽点太多了……

使用 gRPC 时遇到的问题

  1. 首先最让我感到意外的一点是,那么多官方支持的语言里面,居然没有 JS (还是在连 Dart 和 Ruby 都有的情况下)。虽然有个 grpc/grpc-node,但对 JS 生态的支持看上去不是特别理想
  2. Protobuf 生成的代码质量一言难尽:
    1. 在 TS 项目中,想按照官方文档里的例子那样使用 @grpc/grpc-js 的话,需要自动生成类型定义。找了一圈,发现只有 @grpc/proto-loader 自带的 proto-loader-gen-types 生成的还算可用,然而还是有坑,比如引入路径中没有文件扩展名,而在 TS 中使用 ESM + module": "node16" 时文件扩展名是强制的,所以还是需要手动修改生成的代码。另外有个 @bufbuild/protobuf,号称是唯一一个全部通过 Protobuf 兼容性测试的,结果生成的东西 @grpc/grpc-js 压根用不了,只能用他们的配套库 @connectrpc/connect,说是兼容 gRPC ,也只是客户端部分可以发起 gRPC 而已

    2. protoc 生成的 Python 代码也有引入路径问题,如果文件不在根目录下,就会报错找不到模块,于是你还是需要手动修改自动生成的代码

    3. 官方文档太差了,没有更多用例来解释真实场景里是什么样的,比如服务端的部分:

      server.add_insecure_port("[::]:" + PORT)
      
      server.bindAsync(
          `0.0.0.0:${PORT}`,
          gRPC.ServerCredentials.createInsecure(),
          (err, port) => {},
      );
      

      这都 insecure 了,那生产环境中想 secure 该怎么办?

上面的问题 GitHub 也有相关 Issue 讨论,但到目前为止似乎都不了了之了。想问一下有相关经验的佬们:

  1. 我这个需求用 gRPC 是否合适?除此之外还有其他解决方案吗?
  2. 在 TS 和 Python 下,正确的使用姿势分别是什么?除了裸用官方的库 @grpc/grpc-js/grpcio之外,还有其他基于 gRPC 的更好用的框架吗?
2330 次点击
所在节点    程序员
21 条回复
iflint
187 天前
ts 里面用 GRPC 确实比较难受。之前做出过 ts 服务端和 Android (kt) 客户端的通信,kt 里面有明确的接入步骤和官方的插件生成产物。ts 的话也有不少插件但是能很舒服用的不多。目前在用的是 grpc_tools_node_protoc_ts 、ts-proto 、ts-protoc-gen 这几个。

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

https://www.v2ex.com/t/1114626

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

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

© 2021 V2EX