4. 同步通信基础

在微服务架构中,同步通信意味着调用方发出请求后会等待被调用方返回结果,再继续后续逻辑。Azure 上最常见的两种同步通信方式是 REST(基于 HTTP/1.1 或 HTTP/2 的 JSON 语义)与 gRPC(基于 HTTP/2 的二进制协议,使用 Protocol Buffers 定义契约)。两者并非替代关系,而是面向不同约束的两种工具:REST 胜在通用、可读、易调试、跨语言与浏览器友好;gRPC 胜在强类型契约、低序列化开销、双向流与高吞吐低延迟。理解它们的实现方式、性能差异来源以及选择策略,是微服务通信设计的基础。

一、REST 在 Azure 微服务中的实现要点

REST 服务通常以 ASP.NET Core Web API 承载,部署到 Azure Container Apps、AKS 或 App Service。一个典型的订单查询接口如下:

[ApiController]
[Route("api/orders")]
public class OrdersController : ControllerBase
{
    [HttpGet("{id:guid}")]
    public async Task<ActionResult<OrderDto>> Get(Guid id)
    {
        var order = await _repo.FindAsync(id);
        if (order is null) return NotFound();
        return Ok(new OrderDto(order.Id, order.Amount, order.Status));
    }
}

在 Azure 上运行 REST 服务时,需要关注几个工程细节。第一,入口层通常由 Azure API Management 或 Application Gateway 统一暴露,负责路由、限流、JWT 校验与版本管理;第二,服务间调用建议使用 IHttpClientFactory 管理 HttpClient 生命周期,避免套接字耗尽;第三,配合 Azure Monitor 与 Application Insights 采集请求延迟、状态码分布与依赖调用链。REST 的契约通常用 OpenAPI(Swagger)描述,便于生成客户端与文档。

REST 的性能瓶颈主要来自三处:文本 JSON 的序列化/反序列化开销、HTTP/1.1 的队头阻塞与连接复用限制、以及每次请求携带的头部冗余。在 Azure 内部服务间通信中,若 QPS 较高,这些开销会被放大。

二、gRPC 在 Azure 微服务中的实现要点

gRPC 以 .proto 文件定义服务契约,编译生成强类型客户端与服务端桩代码。以下是一个订单服务的契约示例:

service OrderService {
  rpc GetOrder (GetOrderRequest) returns (OrderReply);
}
message GetOrderRequest { string id = 1; }
message OrderReply { string id = 1; double amount = 2; string status = 3; }

服务端在 ASP.NET Core 中通过 Grpc.AspNetCore 注册,客户端通过 Grpc.Net.Client 调用。在 Azure 上部署时,AKS 与 Container Apps 均支持 HTTP/2,但要注意:若前置 Azure Application Gateway 或 API Management,需要确认其对 HTTP/2 端到端(尤其是 gRPC 流式)的支持能力;否则应让调用方直连服务或使用支持 gRPC 的入口。gRPC 默认使用 Protobuf 二进制编码,消息体积通常比等价 JSON 小 30%~60%,序列化耗时也更低,这是其性能优势的主要来源。

三、性能对比:差异从哪里来

把两者放在同一维度比较,才能形成可用的判断依据。下表给出的是典型量级参考(示例性数据,用于说明差异来源,非实测基准):

维度REST / JSONgRPC / Protobuf
编码格式文本 JSON二进制 Protobuf
传输协议HTTP/1.1 或 HTTP/2HTTP/2
契约方式OpenAPI,弱类型.proto,强类型
消息体积(同语义)基准 1.0约 0.4~0.7
流式支持有限(SSE/分块)双向流原生支持
浏览器直调原生支持需 gRPC-Web 代理
可读性与调试高需专用工具

需要强调的是,性能差异并非只由协议决定。服务端线程模型、连接复用、负载均衡策略、序列化库版本都会显著影响结果。因此“gRPC 一定比 REST 快”是过度简化;在低 QPS、消息体小、调用链短的场景中,两者差距可能并不明显。

REST 与 gRPC 同步通信路径与选择决策 调用方服务 Order / BFF REST / JSON HTTP/1.1 · OpenAPI 文本序列化 · 可读 gRPC / Protobuf HTTP/2 · .proto 契约 二进制 · 强类型 Azure 入口层 APIM / App Gateway 路由 · 限流 · 鉴权 后端 微服务 协议选择判断 ① 浏览器/第三方直调、需人工调试 → REST ② 内部高 QPS、低延迟、强类型契约、流式 → gRPC ③ 混合场景:对外 REST + 内部 gRPC,由 BFF 聚合

四、协议选择策略

选择协议时,建议按以下顺序判断。第一,看调用方是谁:浏览器、移动端或第三方合作伙伴通常只能消费 REST,此时 REST 是默认选择;若调用方是内部服务且可控制运行时,gRPC 才具备可行性。第二,看通信模式:请求-响应且消息体小、调用频率低时,REST 的工程成本更低;需要双向流、服务端推送或高频小消息时,gRPC 优势明显。第三,看契约治理需求:若团队需要跨语言强类型契约、自动生成客户端、避免字段拼写错误,gRPC 的 .proto 能显著降低集成成本。第四,看 Azure 入口能力:若必须经过不支持端到端 HTTP/2 的网关,gRPC 的流式能力会受限,此时可考虑 gRPC-Web 或让内部服务直连。

实践建议:对外 API 用 REST + APIM 暴露,内部服务间用 gRPC,由 BFF(Backend for Frontend)负责协议转换与聚合。这样既保留了对外兼容性,又能在内部获得 gRPC 的性能与契约优势。

五、一个可参考的混合落地示例

假设订单服务需要被 Web 前端和库存服务同时调用。前端通过 APIM 调用 REST 接口 GET /api/orders/{id};库存服务则通过 gRPC 调用 OrderService.GetOrder。订单服务同时暴露两种端点:REST 控制器负责对外,gRPC 服务负责对内。两者共享同一个领域层与仓储,避免业务逻辑重复。部署时,REST 端点走 APIM,gRPC 端点通过 AKS 内部 Service 或 Container Apps 的 HTTP/2 入口直连。监控上,REST 依赖 Application Insights 的请求遥测,gRPC 则通过拦截器记录方法级延迟与状态码。

注意:gRPC 在 Azure 上并非“开箱即用”。若使用 App Service,需确认是否支持 HTTP/2 入站;若使用 APIM,需确认 gRPC 透传能力。部署前应做一次端到端连通性验证,避免上线后才发现协议不兼容。

总结来说,REST 与 gRPC 的选择不是非此即彼,而是根据调用方、通信模式、契约治理与 Azure 入口能力综合判断。掌握两者的实现细节与性能差异来源,才能在微服务通信设计中做出有依据的决策。