远程服务调用让微服务间像调用本地方法一样通信。核心问题:用什么协议传输(REST/RPC)、用什么格式序列化(JSON/Protobuf)、如何保证可靠性(超时/重试/幂等)。
| 维度 | REST | RPC |
|---|
| 抽象目标 | 面向资源(名词) | 面向方法(动词) |
| 表达方式 | URL 是资源,HTTP 动词是操作 | 直接调用远程方法 |
| 协议 | HTTP | TCP/HTTP/二进制 |
| 适用场景 | 外部 API、跨平台 | 系统内部高性能通信 |
REST:GET /users/123(获取 123 号用户) RPC:userService.getUserById(123)(调用远程方法)
gRPC 是 Google 开源的高性能 RPC 框架,三大核心优势:
| 优势 | 说明 |
|---|
| Protobuf | 二进制格式,体积比 JSON 小 3-10 倍 |
| HTTP/2 | 多路复用、头部压缩、双向流 |
| 多语言代码生成 | .proto 定义接口,自动生成各语言代码 |
| 模式 | 说明 | 适用场景 |
|---|
| Unary | 一请求一响应 | 普通 API |
| Server Streaming | 一请求流响应 | 实时推送 |
| Client Streaming | 流请求一响应 | 文件上传 |
| Bidirectional Streaming | 双向流 | 即时通讯 |
| 维度 | OpenFeign | Dubbo |
|---|
| 协议 | HTTP 短连接 | TCP 长连接 + 自定义协议 |
| 序列化 | JSON | Hessian/Kryo 二进制 |
| 性能 | 较低 | 高 |
| 服务治理 | 依赖 Spring Cloud 组件 | 内置 |
| 适用场景 | 中小型微服务 | 大型分布式系统 |
分布式场景下超时重试可能触发重复请求,必须保证幂等。
| 方法 | 幂等 | 说明 |
|---|
| GET | 是 | 只读,无副作用 |
| DELETE | 是 | 删除相同资源结果一致 |
| PUT | 是 | 更新/创建,重复结果一致 |
| POST | 否 | 重复提交可能创建多个资源 |
| 方案 | 说明 | 适用场景 |
|---|
| 数据库唯一约束 | 业务字段加唯一索引 | 防重复下单 |
| Redis SetNX | 原子性「设置并检查」 | 接口幂等 Token |
| 乐观锁 | UPDATE ... WHERE version = ? | 库存扣减 |
| 状态机 | 只允许特定状态转换 | 订单状态变更 |
@PostMapping("/orders")
public Order createOrder(@RequestHeader("X-Idempotency-Token") String token,
@RequestBody CreateOrderDTO dto) {
Boolean success = redis.delete("idem:" + token);
if (!success) throw new DuplicateRequestException();
return orderService.create(dto);
}
| 格式 | 大小 | 速度 | 可读性 |
|---|
| JSON | 大 | 中 | 是 |
| Protobuf | 最小 | 最快 | 否(代码生成) |
| Hessian | 小 | 快 | 否 |
选型建议
外部 API → JSON(可读性优先),内部微服务 → Protobuf(性能优先)。
RPC 调用链路上叠加多级缓存可显著降低后端压力:在客户端 → CDN → 反向代理 → 应用 → 数据库各层设置缓存,让请求尽早返回,越靠近用户缓存命中收益越大。完整的多级分流体系(客户端缓存、CDN、反向代理、Redis 分布式缓存、负载均衡分层)详见 透明多级分流。
| 问题 | 解决方案 |
|---|
| 调用超时 | 检查网络连通性;调整连接超时和读超时配置;确认目标服务正常响应 |
| 序列化异常 | 确认客户端和服务端使用相同序列化协议;检查实体类是否实现 Serializable |
| 服务调用失败 | 检查服务是否注册到注册中心;确认版本和分组匹配;检查负载均衡策略 |