首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >gRPC:坏的部分

gRPC:坏的部分

作者头像
萝卜要努力
发布2025-03-11 21:31:08
发布2025-03-11 21:31:08
29900
代码可运行
举报
文章被收录于专栏:萝卜要加油萝卜要加油
运行总次数:0
代码可运行

原文链接🔗: https://kmcd.dev/posts/grpc-the-bad-parts/[1]

gRPC 作为一款高性能的 RPC 框架,在 Google 内部取得了巨大成功,并显著改变了我们部署 API 的方式。然而,它并非完美无缺。创建一个支持代码生成和多语言的 RPC 框架,必然会面临诸多挑战。笔者使用 gRPC 已近十年,在此有必要反思其有待改进之处。

学习曲线:术语与复杂性

首先,我们从一些细节入手。“一元请求”(Unary Request)是指客户端向服务器发送单个请求并接收单个响应的调用。为何 gRPC 必须使用如此晦涩的术语?每次使用都需解释,实在令人困扰。

说到一元请求,gRPC 的实现也显得过于复杂。尽管 gRPC 的流式接口功能强大,但对于简单的 RPC 调用,它引入了不必要的复杂性。这增加了调试 gRPC 调用的难度,因为即使是一元请求也需要分帧,这本是流式传输的特性。Protobuf 编码已足够复杂,无需在非必要之处增加额外的 gRPC 分帧。此外,对于 Web API 而言,使用 cURL 示例来解释 gRPC 的使用方式非常困难。“需要启用服务器反射吗?”这句话我已说过无数次。

这种复杂性也体现在工具层面,尤其是强制的代码生成步骤。对于重视运行时灵活性的动态语言而言,这可能是一个障碍。此外,一些开发者可能会对需要额外构建步骤的技术望而却步。现代 Web 开发已包含众多构建步骤,再增加一个往往令人犹豫。

Web 兼容性:HTTP/2 与 HTTP/3

对 HTTP/2 的依赖最初限制了 gRPC 的普及,因为并非所有平台和浏览器都完全支持它。尽管情况有所改善,但在某些环境下仍是挑战。即使支持 HTTP/2,浏览器也缺乏处理 HTTP Trailers 的能力,因此目前浏览器仍无法“原生”使用 gRPC。gRPC-Web 通过避免使用 Trailers 解决了这个问题,但通常需要额外的代理支持,这非常麻烦。

延迟采用 HTTP/3 协议可能阻碍了 gRPC 充分利用其性能和效率优势。笔者深受 HTTP/2 的“队头阻塞”[2](Head-of-line blocking)问题困扰,而 HTTP/3 本可彻底解决这一问题。一个大力推广 HTTP/2 的框架,却在 HTTP/3 支持上如此挣扎,着实令人费解。

JSON 映射与 Prototext:标准化缺失

早期缺乏标准化的 JSON 映射是另一个失误。这使得习惯于 JSON API 的开发者难以接受 gRPC,我认为 gRPC 从未摆脱这种负面印象。Protobuf 类型与 JSON 之间的映射简化了与现有工具和系统的集成与互操作。当你说“是的,这是一种高效的二进制格式……但如果你想调试,可以设置这个标志来返回 JSON”时,Web 开发者会非常高兴。总之,现在 Protobuf 已有标准的 JSON 映射规则(以及反向),而 Protobuf 文本格式(Prototext)则显得多余。既然有了 JSON,文本格式便不再必要。不如将其废弃。如果大家同意,我愿意假装它从未存在过。

消息大小限制:分块的必要性

大多数 Protobuf 编码器/解码器都期望完全解析整个消息,然后将完整响应提供给消费者,但内存有限,有时我们需要处理更大的消息。有时,我们希望将这些大消息分段传输到其他地方,而不是将其全部保存在内存中。

因此,如果需要上传大型文件,我们需要实现某种文件分块机制。尽管分块是处理大文件的合理方案,但 gRPC 缺乏标准化的方法,可能导致实现不一致,增加开发工作量。

例如,以下是使用 gRPC 上传文件的示例:

代码语言:javascript
代码运行次数:0
运行
复制
syntax = "proto3";

package file_service;

service FileService {
  rpc Upload(stream UploadRequest) returns(UploadResponse);
}

message UploadRequest {
  string file_name = 1;
  bytes chunk = 2;
}

message UploadResponse {
  string etag = 1;
}

这既是 Protobuf 的优势,也是劣势。在 Protobuf 中定义这个概念非常容易,但实际实现却可能繁琐且容易出错。尽管 gRPC 的创建者 Google 已为其 API 找到了解决方案,但缺乏标准化的方法,让其他人需要重复造轮子。

你可能会想:“Google 在其大多数 API 中使用 gRPC,显然他们已经解决了这个问题。” 你是对的。他们确实有一个 gRPC 和 HTTP 版本用于下载(可能很大的)文件。我们可以直接比较 gRPC[3]和HTTP[4]版本,gRPC 版本明显更复杂。

社区活跃度:依赖管理之殇

我发现 gRPC/Protobuf 社区的活跃度不高。一些网站缺乏明显的活动,可能会让人觉得 gRPC 停滞不前或维护不力。这可能会阻碍潜在的采用者,并减缓社区的增长。这可能是因为选择太多,导致人们难以在 GitHub 问题之外找到愿意讨论 gRPC 的人。

很长一段时间里,每当看到一个代码库使用 Protobuf,我都会发现一个奇怪的脚本,用于下载随机的 Protobuf 文件,以高度自定义的方式放置它们,并执行一系列极其复杂的 protoc 调用。只有 Google 才会认为不解决依赖管理问题就是解决依赖管理问题。Google 有自己的依赖管理方式,我们只能望其项背。

持续改进:未来可期

尽管我对 gRPC 提出了批评,但我希望这些评论是建设性的。读到这里的人应该知道,许多问题已经或正在得到解决:

  • 一些 gRPC 实现已支持 HTTP/3。ConnectRPC 让使用 HTTP/3 的 gRPC 变得非常容易。
  • 由于 Protobuf 规范已包含标准的JSON 映射[5],我不再需要担心文本格式。
  • 如果你知道去哪里寻找,gRPC 社区其实非常活跃。例如,Buf Slack[6] 是一个很好的资源。
  • Buf CLI [7]是一款出色的 gRPC 工具。它完全取代了 protoc,并增加了 linting、破坏性变更检测、gRPC 版 cURL、与 Buf Schema Registry 的集成(真正的依赖管理!)等功能。此外,越来越多的工具开始支持 gRPC,例如 Postman、Insomnia 和 k6。

结论

尽管 gRPC 取得了不可否认的成功,但承认其不足之处至关重要,这有助于其持续发展和改进。通过解决学习曲线、兼容性、标准化和社区参与等方面的问题,我们可以释放 gRPC 的全部潜力,使其成为所有开发者都能轻松使用的工具

延伸阅读

再谈 gRPC 的 Trailers 设计[8]

引用链接

[1]https://kmcd.dev/posts/grpc-the-bad-parts/

[2]队头阻塞”: https://http3-explained.haxx.se/en/why-quic/why-tcphol

[3]gRPC: https://github.com/googleapis/google-cloud-go/blob/v0.114.0/storage/grpc_client.go#L996-L1152

[4]HTTP: https://github.com/googleapis/google-cloud-go/blob/v0.114.0/storage/http_client.go#L888-L911

[5]标准的JSON 映射: https://protobuf.dev/programming-guides/proto3/#json

[6]Buf Slack: https://buf.build/links/slack

[7]Buf CLI : https://buf.build/docs/ecosystem/cli-overview

[8]再谈 gRPC 的 Trailers 设计: https://taoshu.in/grpc-trailers.html

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

本文分享自 萝卜要加油 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 学习曲线:术语与复杂性
  • Web 兼容性:HTTP/2 与 HTTP/3
  • JSON 映射与 Prototext:标准化缺失
  • 消息大小限制:分块的必要性
  • 社区活跃度:依赖管理之殇
  • 持续改进:未来可期
  • 结论
  • 延伸阅读
    • 引用链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档