跳到主要内容

服务通信方式

问题

微服务之间如何通信?同步通信和异步通信各有什么适用场景?REST 和 gRPC 怎么选?

答案

通信方式分类

维度同步异步
特点请求-响应,调用方等待结果发送消息后不等待,通过回调/轮询获取结果
协议HTTP REST、gRPC、FeignMQ(Kafka、RocketMQ)、事件总线
耦合度较高(直接依赖)低(通过消息中间件解耦)
适用即时响应、查询操作不需要即时响应、事件通知

REST vs gRPC

对比RESTgRPC
协议HTTP/1.1(JSON)HTTP/2(Protobuf)
序列化JSON(文本)Protobuf(二进制)
性能较低高(二进制 + 多路复用)
流式通信不原生支持4 种流模式
类型安全弱(JSON)强(.proto 定义)
浏览器支持原生支持需要 gRPC-Web
生态最广泛快速增长
适用对外 API、BFF内部服务间高性能通信
gRPC 服务定义
syntax = "proto3";

service OrderService {
rpc CreateOrder (CreateOrderRequest) returns (CreateOrderResponse);
rpc GetOrder (GetOrderRequest) returns (Order);
// 服务端流式
rpc ListOrders (ListOrdersRequest) returns (stream Order);
}

message CreateOrderRequest {
string user_id = 1;
string product_id = 2;
int32 quantity = 3;
}

Spring Cloud OpenFeign

声明式 HTTP 客户端,简化服务间调用。

Feign 客户端
@FeignClient(name = "inventory-service", fallback = InventoryFallback.class)
public interface InventoryClient {

@PostMapping("/api/inventory/deduct")
Result<Boolean> deductStock(@RequestBody DeductRequest request);

@GetMapping("/api/inventory/{productId}")
Result<Integer> getStock(@PathVariable String productId);
}

// 降级处理
@Component
public class InventoryFallback implements InventoryClient {
@Override
public Result<Boolean> deductStock(DeductRequest request) {
return Result.fail("库存服务不可用");
}

@Override
public Result<Integer> getStock(String productId) {
return Result.fail("库存服务不可用");
}
}

异步通信(事件驱动)

领域事件驱动
// 订单服务:发布订单创建事件
@Service
public class OrderService {
@Autowired
private RocketMQTemplate mqTemplate;

@Transactional
public Order createOrder(OrderDTO dto) {
Order order = orderRepository.save(dto.toEntity());
// 发布领域事件
mqTemplate.convertAndSend("order-events",
new OrderCreatedEvent(order.getId(), order.getUserId()));
return order;
}
}

// 积分服务:订阅事件
@Component
@RocketMQMessageListener(topic = "order-events", consumerGroup = "points-group")
public class PointsEventListener implements RocketMQListener<OrderCreatedEvent> {
@Override
public void onMessage(OrderCreatedEvent event) {
pointsService.addPoints(event.getUserId(), 10);
}
}

通信方式选择

场景推荐方式原因
查询数据同步(Feign/REST)需要即时返回结果
下单扣库存同步 + 分布式事务强一致性要求
订单→通知异步(MQ)不影响主流程
订单→积分异步(MQ)最终一致即可
内部高频调用gRPC高性能、低延迟
对外 APIREST通用性强

常见面试问题

Q1: 微服务之间怎么调用?

答案

两种主要方式:

  1. 同步调用:OpenFeign(声明式 REST)、gRPC。适用于需要即时响应的场景
  2. 异步消息:通过 MQ 发布/订阅事件。适用于不需要即时响应、解耦的场景

选择原则:能异步就异步(减少耦合和级联故障),需要即时响应才用同步。

Q2: 服务调用失败怎么办?

答案

  1. 超时控制:设置合理的超时时间(如 3 秒),避免无限等待
  2. 重试:幂等接口可以配置重试(如 Feign 默认不重试,需手动配置)
  3. 熔断降级:使用 Sentinel 或 Resilience4j,快速失败并返回兜底数据
  4. 异步补偿:同步调用失败时发消息异步重试

Q3: 如何减少服务间调用次数?

答案

  1. BFF 聚合层:前端需要的数据在 BFF 层聚合,减少前端多次调用
  2. 数据冗余:将高频查询的数据冗余到本服务(通过事件同步)
  3. 批量查询:避免循环调用,改为批量接口
  4. 缓存:本地缓存 + Redis 缓存减少远程调用

相关链接