强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

微服务拆分精讲 / 第 07 章:服务通信

第 07 章:服务通信

服务间的通信方式决定了系统的耦合度、性能和可靠性。选对通信模式,是微服务成功的关键。


7.1 通信模式总览

7.1.1 同步 vs 异步

  同步通信 (Synchronous)
  ──────────────────────────────

  服务A ──请求──▶ 服务B
  服务A ◀──响应── 服务B

  特点:调用方等待响应,阻塞直到完成


  异步通信 (Asynchronous)
  ──────────────────────────────

  服务A ──消息──▶ [消息队列] ──消费──▶ 服务B

  特点:调用方发送消息后立即返回,不等待响应

7.1.2 通信模式矩阵

模式参与方数量通信方式示例
请求-响应1:1同步REST API, gRPC
单向通知1:1异步事件通知
发布-订阅1:N异步广播事件
请求-异步响应1:1异步回调模式
  请求-响应               发布-订阅
  ─────────              ─────────
  A ──请求──▶ B          A ──事件──▶ Topic
  A ◀──响应── B               ├──▶ B
                              ├──▶ C
                              └──▶ D

7.2 同步通信:REST

7.2.1 REST API 设计规范

规范说明示例
资源命名使用名词复数/api/v1/users
HTTP 方法GET/POST/PUT/DELETE 语义GET /users/{id}
状态码正确使用 HTTP 状态码200/201/400/404/500
版本化URL 或 Header 中体现版本/api/v1/
分页列表接口支持分页?page=1&size=20
  REST API 设计示例:

  ┌────────┬──────────────────────┬───────────────┐
  │ 方法    │ 路径                 │ 说明          │
  ├────────┼──────────────────────┼───────────────┤
  │ GET    │ /api/v1/users        │ 获取用户列表   │
  │ GET    │ /api/v1/users/{id}   │ 获取单个用户   │
  │ POST   │ /api/v1/users        │ 创建用户      │
  │ PUT    │ /api/v1/users/{id}   │ 更新用户      │
  │ DELETE │ /api/v1/users/{id}   │ 删除用户      │
  │ GET    │ /api/v1/users/{id}/orders │ 用户的订单 │
  └────────┴──────────────────────┴───────────────┘

7.2.2 REST 的优缺点

维度优势劣势
易用性HTTP 通用,易理解冗余头部开销
调试浏览器/Postman 可直接调试
性能JSON 序列化开销大
类型安全缺乏强类型约束
代码生成需要 OpenAPI/Swagger
流式传输不支持流式通信

7.2.3 OpenAPI/Swagger 规范

# openapi.yaml
openapi: 3.0.0
info:
  title: User Service API
  version: 1.0.0
paths:
  /api/v1/users/{id}:
    get:
      summary: 获取用户详情
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: 用户不存在
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
          format: email

7.3 同步通信:gRPC

7.3.1 gRPC 概述

gRPC 是 Google 开发的高性能 RPC 框架,基于 HTTP/2 和 Protocol Buffers。

  gRPC 通信流程:

  ┌──────────┐                          ┌──────────┐
  │ 客户端    │                          │ 服务端    │
  │          │      HTTP/2 连接          │          │
  │ Proto    │ ◀══════════════════════▶ │ Proto    │
  │ Client   │   二进制传输 (Protobuf)   │ Server   │
  │          │                          │          │
  │ .proto   │  ┌──────────────────┐   │ .proto   │
  │ 文件生成  │  │ IDL 接口定义     │   │ 文件生成  │
  │ 客户端桩  │  │ service UserService│  │ 服务端骨架│
  └──────────┘  │ {                  │  └──────────┘
                │   rpc GetUser      │
                │   (GetUserReq)     │
                │   returns          │
                │   (UserResp)       │
                │ }                  │
                └──────────────────┘

7.3.2 Protocol Buffers 定义

// user.proto
syntax = "proto3";

package user;

option java_package = "com.example.user";

service UserService {
  rpc GetUser (GetUserRequest) returns (UserResponse);
  rpc ListUsers (ListUsersRequest) returns (ListUsersResponse);
  rpc CreateUser (CreateUserRequest) returns (UserResponse);
  rpc WatchUser (WatchUserRequest) returns (stream UserEvent); // 服务端流
}

message GetUserRequest {
  string id = 1;
}

message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
  int64 created_at = 4;
}

message ListUsersRequest {
  int32 page = 1;
  int32 size = 2;
}

message ListUsersResponse {
  repeated UserResponse users = 1;
  int32 total = 2;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
}

message WatchUserRequest {
  string user_id = 1;
}

message UserEvent {
  string event_type = 1;  // CREATED, UPDATED, DELETED
  UserResponse user = 2;
  int64 timestamp = 3;
}

7.3.3 gRPC 四种通信模式

  1. 一元 RPC (Unary)
     客户端 ──请求──▶ 服务端
     客户端 ◀──响应── 服务端

  2. 服务端流式 (Server Streaming)
     客户端 ──请求──▶ 服务端
     客户端 ◀──stream── 服务端
     客户端 ◀──stream── 服务端
     客户端 ◀──stream── 服务端

  3. 客户端流式 (Client Streaming)
     客户端 ──stream──▶ 服务端
     客户端 ──stream──▶ 服务端
     客户端 ──stream──▶ 服务端
     客户端 ◀──响应── 服务端

  4. 双向流式 (Bidirectional Streaming)
     客户端 ──stream──▶ 服务端
     客户端 ◀──stream── 服务端
     客户端 ──stream──▶ 服务端
     客户端 ◀──stream── 服务端

7.3.4 REST vs gRPC 全面对比

维度RESTgRPC
协议HTTP/1.1HTTP/2
数据格式JSON (文本)Protobuf (二进制)
性能较低极高(2-10 倍)
类型安全弱 (依赖文档)强 (IDL 编译时检查)
代码生成OpenAPI (可选)必须 (protoc)
浏览器支持✅ 原生支持⚠️ 需要 gRPC-Web
流式传输❌ 不支持✅ 四种模式
调试✅ curl/浏览器⚠️ 需要专用工具
学习曲线
适用场景外部 API服务间高性能通信

7.4 通信模式选型

7.4.1 选型决策树

  需要同步响应吗?
  │
  ├── 是 → 需要高性能/低延迟?
  │        │
  │        ├── 是 → 使用 gRPC
  │        │        (服务间内部通信)
  │        │
  │        └── 否 → 使用 REST
  │                  (外部 API / 简单场景)
  │
  └── 否 → 需要保证消息不丢失?
           │
           ├── 是 → 使用消息队列
           │        (Kafka / RabbitMQ)
           │
           └── 否 → 使用事件通知
                    (轻量级异步)

7.4.2 通信方式适用场景

场景推荐方式理由
外部客户端 APIREST兼容性好,易调试
服务间内部调用(简单)REST实现简单,团队熟悉
服务间内部调用(高性能)gRPC低延迟,强类型
实时推送/流式gRPC Streaming原生流式支持
事件通知消息队列解耦、可靠
批量数据同步消息队列削峰填谷
实时聊天/协作WebSocket / gRPC 双向流双向实时通信

7.5 服务发现(Service Discovery)

7.5.1 服务发现方式

  客户端发现                    服务端发现
  ────────────                ────────────

  ┌────────┐                  ┌────────┐
  │ 客户端  │                  │ 客户端  │
  └───┬────┘                  └───┬────┘
      │                           │
      ▼                           ▼
  ┌──────────┐               ┌──────────┐
  │ 服务注册  │               │ 负载均衡  │
  │ 中心     │               │ / 代理   │
  │(Eureka/  │               │(LB/Nginx)│
  │ Consul)  │               └────┬─────┘
  └──────────┘                    │
      │                           ▼
      ▼                       ┌──────────┐
  ┌──────────┐               │ 服务实例  │
  │ 服务实例  │               └──────────┘
  └──────────┘

7.5.2 注册中心对比

注册中心一致性协议健康检查配置管理适用场景
ConsulRaftHTTP/TCP/gRPCKV Store通用,多数据中心
EtcdRaftTTL/LeaseKV StoreK8s 生态
NacosAP/CP 可选HTTP/TCP配置中心Spring Cloud Alibaba
ZooKeeperZAB会话节点传统 Java 项目
EurekaAP心跳Netflix 生态(已维护模式)

7.6 弹性通信模式

7.6.1 超时、重试与熔断

  ┌──────────────────────────────────────────────────────────┐
  │                 弹性通信三板斧                             │
  ├──────────────────────────────────────────────────────────┤
  │                                                          │
  │  1. 超时 (Timeout)                                       │
  │  ┌────────┐  ──请求──▶  ┌────────┐                      │
  │  │ 服务A   │  3秒超时    │ 服务B   │                      │
  │  │        │  ◀─超时!──  │ (卡住)  │                      │
  │  └────────┘             └────────┘                      │
  │                                                          │
  │  2. 重试 (Retry)                                         │
  │  ┌────────┐  ──请求1──▶ ┌────────┐                      │
  │  │ 服务A   │  ◀─失败──  │ 服务B   │                      │
  │  │        │  ──请求2──▶ │        │                      │
  │  │        │  ◀─成功──   │        │                      │
  │  └────────┘             └────────┘                      │
  │                                                          │
  │  3. 熔断 (Circuit Breaker)                               │
  │  ┌────────┐             ┌────────┐                      │
  │  │ 服务A   │  ──请求──▶  │ 服务B   │  (连续失败)          │
  │  │        │             └────────┘                      │
  │  │  熔断器 │  ──直接──▶  返回降级响应                     │
  │  │ CLOSED │             (不再调用B)                      │
  │  │   ↓    │                                             │
  │  │  OPEN  │  一段时间后 ──半开──▶  探测请求               │
  │  └────────┘             恢复? CLOSED : OPEN              │
  └──────────────────────────────────────────────────────────┘

7.6.2 熔断器状态机

  ┌─────────────┐    失败率超过阈值    ┌─────────────┐
  │   CLOSED    │ ──────────────────▶ │    OPEN     │
  │  (正常状态)  │                     │  (熔断状态)  │
  │  所有请求    │                     │  所有请求    │
  │  通过       │                     │  直接拒绝    │
  └──────┬──────┘                     └──────┬──────┘
         │                                   │
         │  正常响应                          │ 等待超时后
         │                                   ▼
         │                            ┌──────────────┐
         │◀────────────────────────── │  HALF-OPEN   │
         │    探测成功,恢复            │  (半开状态)   │
         │                            │  允许少量请求  │
         │                            └──────────────┘
         │                                   │
         │                            探测失败│
         │                                   ▼
         │                            回到 OPEN 状态

7.6.3 Resilience4j 示例

// 熔断器配置
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
    .failureRateThreshold(50)           // 失败率阈值 50%
    .waitDurationInOpenState(Duration.ofSeconds(30))  // 熔断等待 30 秒
    .slidingWindowSize(10)              // 滑动窗口 10 次请求
    .minimumNumberOfCalls(5)            // 最少 5 次调用才计算
    .build();

CircuitBreaker circuitBreaker = CircuitBreaker.of("userService", config);

// 使用
Supplier<User> decoratedSupplier = CircuitBreaker
    .decorateSupplier(circuitBreaker, () -> userService.getUser(userId));

Try<User> result = Try.ofSupplier(decoratedSupplier)
    .recover(CallNotPermittedException.class, e -> getFallbackUser())
    .recover(Exception.class, e -> getDefaultUser());

7.7 业务场景:电商系统的通信设计

  ┌───────────────────────────────────────────────────────────┐
  │              电商系统通信模式选型                            │
  ├───────────────────────────────────────────────────────────┤
  │                                                           │
  │  外部 API(客户端 → 网关):                                │
  │  └─ REST / HTTPS                                          │
  │                                                           │
  │  服务间同步调用:                                          │
  │  ├─ 订单服务 → 用户服务 (查询用户): REST                   │
  │  ├─ 订单服务 → 商品服务 (查询商品): gRPC                   │
  │  └─ 订单服务 → 库存服务 (扣库存): gRPC (高性能)            │
  │                                                           │
  │  服务间异步事件:                                          │
  │  ├─ 订单已创建 → Kafka → 支付服务/库存服务/通知服务        │
  │  ├─ 支付已完成 → Kafka → 订单服务/物流服务                 │
  │  └─ 商品已发货 → Kafka → 通知服务/用户服务                 │
  │                                                           │
  │  实时通信:                                                │
  │  └─ WebSocket / gRPC Streaming (订单状态实时推送)          │
  └───────────────────────────────────────────────────────────┘

⚠️ 注意事项

  1. 同步调用链不要太长——超过 3 层的同步调用应考虑异步化
  2. 设置合理的超时——每个调用都必须有超时,避免无限等待
  3. 重试要有退避策略——指数退避 + 抖动,避免重试风暴
  4. 熔断要配合降级——熔断后要有兜底响应
  5. gRPC 调试不如 REST 方便——确保有合适的调试工具

📖 扩展阅读

  1. gRPC Documentation (grpc.io) — gRPC 官方文档
  2. Resilience4j (resilience4j.readme.io) — Java 弹性通信库
  3. Sam Newman - Building Microservices, Chapter 4 — 同步通信
  4. Netflix Hystrix (已进入维护模式,推荐 Resilience4j 替代)
  5. Web API Design — API 设计最佳实践

本章小结

要点说明
同步通信REST(通用)和 gRPC(高性能)两种主要方式
异步通信消息队列解耦服务,详见第 08 章
服务发现Consul/Etcd/Nacos 是主流选择
弹性模式超时 + 重试 + 熔断 = 稳定的服务通信
选型原则外部用 REST,内部高性能用 gRPC,异步用 MQ

📌 下一章第 08 章:消息队列 — 深入消息队列、事件驱动架构与最终一致性。