3. 服务通信基础与协议选型

微服务拆开之后,服务之间“怎么说话”就成了架构里最先要定下来的事。协议选型不是追求最新最酷,而是让每一次调用的语义、时延、吞吐、可观测性和运维成本都落在可接受的范围内。在 Google Cloud 上,常见的四种通信方式各有清晰的位置:REST 适合对外与通用集成,gRPC 适合内部高频强类型调用,HTTP/2 是承载 gRPC 与多路复用的传输底座,WebSocket 适合服务端主动推送的双向长连接。理解它们的差异,比记住“哪个更快”更重要。

四种协议的本质差异

REST 通常指基于 HTTP/1.1 或 HTTP/2 的 JSON over HTTP,用 URL 表达资源、用方法表达动作,语义直观、调试方便,浏览器和任何语言都能直接消费。它的代价是文本序列化开销大、每次请求都要携带较多元数据,且 HTTP/1.1 下同一连接难以真正并行。

gRPC 建立在 HTTP/2 之上,用 Protocol Buffers 定义服务契约并做二进制序列化。它天然支持四种调用模式:一元调用、服务端流、客户端流、双向流。强类型契约让跨语言代码生成和向后兼容更可控,二进制编码让报文更小、解析更快,HTTP/2 的多路复用让一个连接上可以并发多个请求,避免了 HTTP/1.1 的队头阻塞。

HTTP/2 本身不是一种“业务协议”,而是传输层能力:二进制分帧、多路复用、头部压缩(HPACK)、服务端推送和流优先级。gRPC 正是把这些能力用满的典型。理解 HTTP/2 有助于判断:当内部调用量大、连接数多时,多路复用能显著减少连接建立与 TLS 握手的开销。

WebSocket 通过一次 HTTP 升级握手建立全双工长连接,之后双方可以随时互发消息。它适合聊天、协同编辑、实时行情、任务进度推送等“服务端需要主动通知客户端”的场景。代价是连接需要保活、状态需要管理,且不像 REST 那样天然无状态、易水平扩展。

Google Cloud 微服务通信协议选型全景 按调用方向、时延敏感度与连接形态选择,而非按新旧排序 外部客户端 浏览器 / 移动 App 第三方系统 调试工具 / curl API 网关 / 负载均衡 Cloud Endpoints / Apigee Cloud Load Balancing 协议转换与鉴权 内部微服务 订单 / 库存 / 支付 Cloud Run / GKE Service Mesh 侧车 异步与推送 Pub/Sub WebSocket 网关 实时通知 REST/JSON gRPC/HTTP2 WebSocket 协议特性与适用判断 协议 编码与传输 典型时延/吞吐 最佳场景 主要代价 REST JSON 文本 / HTTP1.1 毫秒级,吞吐中等 对外 API、CRUD 报文大、无强类型 gRPC Protobuf 二进制 / HTTP2 低时延,高吞吐 内部高频调用、流式 调试门槛、浏览器支持弱 HTTP/2 二进制分帧 / 多路复用 减少连接与握手开销 gRPC 底座、多请求并发 需 TLS、代理需支持 WebSocket 全双工长连接 / 帧 推送时延极低 实时推送、双向交互 连接保活、状态管理

在 Google Cloud 上如何落地选型

对外暴露的 API 优先用 REST。Cloud Endpoints 和 Apigee 对 OpenAPI 的支持成熟,鉴权、配额、审计都能直接挂上去;浏览器和第三方系统无需额外 SDK 即可调用。如果外部客户端确实需要流式或高频交互,可以在网关层做 gRPC-Web 或 JSON 转码,把外部 REST 请求翻译成内部 gRPC 调用,而不是让外部直接说 gRPC。

内部服务之间优先用 gRPC。Cloud Run 和 GKE 都原生支持 HTTP/2,gRPC 服务可以正常做健康检查和负载均衡。用 Protocol Buffers 定义 service 和 message,通过 protoc 生成各语言客户端,契约即文档。一个典型的一元调用定义如下:

service OrderService {
  rpc GetOrder (GetOrderRequest) returns (Order);
  rpc WatchOrders (WatchRequest) returns (stream OrderEvent);
}

message GetOrderRequest {
  string order_id = 1;
}

message Order {
  string order_id = 1;
  string status   = 2;
  int64  amount_cents = 3;
}

当需要服务端持续推送订单状态变化时,用 stream OrderEvent 的服务端流,比客户端轮询 REST 接口更省资源、时延更低。双向流则适合需要客户端和服务端持续对话的场景,例如实时协作或长任务进度回传。

WebSocket 在 Google Cloud 上通常不直接暴露给公网,而是放在 Cloud Run 或 GKE 的 WebSocket 网关后面,配合 Pub/Sub 做扇出。客户端与网关建立长连接,网关订阅 Pub/Sub 主题,把事件推给对应连接。这样业务服务仍然是无状态的,推送的连接状态集中在网关层,扩容和故障恢复都更简单。

选型时先问三个问题:调用方是谁(外部还是内部)、是否需要服务端主动推送、单次调用的时延和吞吐要求是多少。三个问题的答案基本就能定位到 REST、gRPC 或 WebSocket。

性能权衡与常见误区

gRPC 的二进制编码和 HTTP/2 多路复用确实能降低单次调用的网络开销,但这不意味着所有内部调用都必须换成 gRPC。如果调用频率很低、报文很小,REST 的可读性和调试便利性反而更有价值。真正需要关注的是高频、大报文、强类型契约和流式这几类场景。

另一个常见误区是把 HTTP/2 当成“打开就更快”。HTTP/2 的多路复用需要 TLS 和代理支持,如果中间有只支持 HTTP/1.1 的负载均衡或旧版代理,连接会被降级,多路复用失效。在 GKE 上使用 gRPC 时,要确认 Service 的负载均衡策略和 Ingress 支持 HTTP/2,否则可能出现连接复用异常或请求分布不均。

WebSocket 的代价常被低估。长连接意味着服务端要维护连接状态、处理心跳和断线重连,连接数上限和内存占用都需要容量规划。如果只是“服务端偶尔通知一下”,用 Pub/Sub 加客户端轮询或 Server-Sent Events 可能更简单;只有真正需要低时延双向交互时,WebSocket 才是合适选择。

判断维度 REST gRPC WebSocket
调用方向 客户端请求 / 服务端响应 请求响应 + 双向流 全双工
契约形式 OpenAPI / JSON Protobuf IDL 自定义消息格式
浏览器直连 原生支持 需 gRPC-Web 原生支持
典型 GCP 组件 Cloud Endpoints、Apigee Cloud Run、GKE、Traffic Director Cloud Run、Pub/Sub、GKE 网关

实际项目中,三种协议往往共存:外部 REST 入口、内部 gRPC 调用、实时 WebSocket 推送。关键是让每种协议出现在它最合适的位置,而不是用一种协议硬套所有场景。选型确定后,把契约、超时、重试和可观测性一起设计进去,通信层才不会成为微服务治理的短板。