4. 微服务通信基础与协议选择
微服务拆开之后,服务之间怎么“说话”就成了架构成败的关键。通信方式选错,往往不是性能差一点,而是把整个系统拖进耦合、超时、雪崩的泥潭。本节围绕同步与异步两条主线,梳理 REST/HTTP、gRPC、GraphQL 以及消息队列与事件驱动在 OCI(Oracle Cloud Infrastructure)中的适用场景,并给出可落地的判断依据。
同步与异步:先分清“等不等结果”
同步通信指调用方发出请求后阻塞等待响应,典型如 REST 和 gRPC。它的优点是语义直观、链路清晰、便于调试;代价是调用方与被调方在时间上强绑定,被调方变慢或不可用会直接传导为调用方超时。异步通信指调用方把消息投递到中间件后立即返回,由消费方在稍后处理,典型如 OCI Streaming、OCI Queue。它解耦了时间与可用性,但引入了最终一致性、消息重复与顺序问题。
判断标准可以归纳为三点:是否需要立即拿到结果——查询类、校验类通常同步;是否能容忍最终一致——通知、审计、积分累计通常异步;调用方是否必须知道被调方存在——若不应知道,则应走事件而非直接调用。
REST/HTTP:对外契约的首选
REST 以资源为中心,用 HTTP 方法表达动作、用状态码表达结果,天然适配浏览器、移动端和第三方集成。在 OCI 中,典型落地方式是 API Gateway 暴露统一入口,后端由 OKE 中的服务或 Functions 承载,网关负责鉴权、限流、路由与 TLS 终止。示例:订单查询接口 GET /orders/{id},网关配置 1000 请求/秒的限流,后端返回 200 与 JSON 体;若订单不存在返回 404,参数非法返回 400。这些状态码本身就是契约的一部分,客户端据此决定重试还是提示用户。
REST 的短板在于:每次调用携带完整文本头,序列化开销大;接口演进依赖版本号(如 /v2/orders),容易产生版本碎片;没有强类型契约,字段变更靠文档约束。因此它更适合“对外、低频、可读性优先”的场景,而不是内部高频调用。
gRPC:内部高频链路的利器
gRPC 基于 HTTP/2 多路复用与 Protobuf 二进制编码,天然支持一元调用、服务端流、客户端流和双向流。它的接口由 .proto 文件定义,编译期即校验字段类型,契约强、体积小、延迟低。在 OKE 内部,订单服务调用库存服务扣减库存,若 QPS 达到数千且要求 P99 在 20ms 内,gRPC 通常比 REST 更合适。
service Inventory {
rpc Deduct(DeductRequest) returns (DeductReply);
}
message DeductRequest {
string sku = 1;
int32 qty = 2;
string orderId = 3;
}
需要注意的是,gRPC 依赖 HTTP/2,浏览器直连支持有限,通常需要 gRPC-Web 或网关转换;同时 Protobuf 的字段编号一旦发布不可随意更改,删除字段应保留编号并标记 reserved,否则会造成新旧版本解析错乱。
GraphQL:聚合查询的折中方案
GraphQL 让客户端声明“我要哪些字段”,由服务端一次返回,避免 REST 的多次往返与字段冗余。它适合 BFF(Backend for Frontend)层:移动端首页需要用户、订单、优惠券三类数据,若分别调用三个 REST 接口需三次往返,而 GraphQL 一次查询即可聚合。在 OCI 中,GraphQL 服务通常部署在 OKE,后端再以 gRPC 或 REST 调用各领域服务。
但 GraphQL 也带来新问题:查询复杂度不可控,恶意深嵌套可能拖垮后端,需要设置深度限制与查询成本上限;缓存比 REST 的 URL 缓存更复杂;错误处理返回 200 加 errors 数组,监控需专门适配。因此它更适合“客户端多样、聚合需求强”的场景,而非所有接口一律 GraphQL 化。
消息队列与事件驱动:解耦与削峰
当调用方不需要立即结果时,应转向异步。OCI Queue 适合点对点任务分发:订单创建后投递一条“生成发票”消息,发票服务消费并处理,失败则重投,超过次数进入死信队列人工排查。OCI Streaming 适合发布/订阅与事件流:订单状态变更事件被通知服务、积分服务、数据仓库各自订阅,互不影响。
异步通信必须处理三个工程问题:幂等——消息可能重复投递,消费方需以业务唯一键(如 orderId)去重;顺序——同一订单的事件应保证有序,可用分区键将同一订单路由到同一分区;可观测——消息积压、消费延迟、死信数量需纳入监控,OCI 控制台与 Metrics 可观察队列深度与消费速率。
选型决策要点
| 维度 | REST/HTTP | gRPC | GraphQL | 消息/事件 |
|---|---|---|---|---|
| 通信模式 | 同步 | 同步/流 | 同步 | 异步 |
| 契约强度 | 弱(文档) | 强(proto) | 中(Schema) | 中(消息格式) |
| 典型延迟 | 中 | 低 | 中 | 不适用 |
| OCI 承载 | API Gateway | OKE/服务网格 | OKE + BFF | Queue/Streaming |
| 主要风险 | 版本碎片 | 浏览器兼容 | 查询复杂度 | 重复与顺序 |
实际系统中,这四种方式往往并存:对外 REST 暴露 API,内部 gRPC 承载核心链路,BFF 用 GraphQL 聚合,跨域状态变更走事件。关键不是选一个“最好”的协议,而是让每条通信路径都与其一致性要求、延迟预算和耦合容忍度相匹配。