【架构实战】编排vs协同:微服务通信架构选型

一、微服务通信概述

微服务架构中,服务间通信是核心问题:

通信模式:

  • 同步通信(REST、gRPC)
  • 异步通信(消息队列、事件驱动)
  • 编排模式(Orchestration)
  • 协同模式(Choreography)

选型考虑因素:

  • 业务复杂度
  • 性能要求
  • 一致性需求
  • 可维护性

二、编排模式(Orchestration)

1. 核心概念

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                       编排模式                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│              ┌───────────────────────┐                         │
│              │     编排器(Orchestrator)│                         │
│              │     中心化控制          │                         │
│              └───────────┬───────────┘                         │
│                          │                                       │
│            ┌─────────────┼─────────────┐                       │
│            │             │             │                       │
│            ▼             ▼             ▼                       │
│      ┌─────────┐   ┌─────────┐   ┌─────────┐              │
│      │ 服务A   │   │ 服务B   │   │ 服务C   │              │
│      └─────────┘   └─────────┘   └─────────┘              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2. 同步编排实现

java 复制代码
// 订单编排器
@Service
public class OrderOrchestrator {
    
    @Autowired
    private ProductService productService;
    @Autowired
    private PaymentService paymentService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private LogisticsService logisticsService;
    
    @Transactional
    public OrderResult createOrder(OrderRequest request) {
        // 1. 验证商品
        List<Product> products = productService.validateProducts(request.getItems());
        
        // 2. 扣减库存
        inventoryService.deductStock(request.getItems());
        
        // 3. 创建订单
        Order order = orderService.createOrder(request);
        
        // 4. 处理支付
        PaymentResult payment = paymentService.processPayment(order);
        
        if (!payment.isSuccess()) {
            // 支付失败,回滚库存
            inventoryService.rollbackStock(request.getItems());
            throw new PaymentException("支付失败");
        }
        
        // 5. 触发配送
        logisticsService.createDelivery(order);
        
        // 6. 返回结果
        return OrderResult.builder()
            .orderId(order.getId())
            .paymentId(payment.getPaymentId())
            .build();
    }
}

3. 异步编排实现

java 复制代码
// Saga编排器
@Service
public class OrderSagaOrchestrator {
    
    @Autowired
    private KafkaTemplate kafkaTemplate;
    
    public String startOrderSaga(OrderRequest request) {
        String sagaId = UUID.randomUUID().toString();
        
        // 启动Saga
        SagaState state = SagaState.builder()
            .sagaId(sagaId)
            .currentStep(0)
            .status(SagaStatus.STARTED)
            .request(request)
            .build();
        
        // 保存Saga状态
        sagaStateStore.save(state);
        
        // 发送第一个步骤
        kafkaTemplate.send("saga-order", sagaId, new CreateOrderStep(sagaId, request));
        
        return sagaId;
    }
    
    // 处理Saga步骤结果
    public void handleStepResult(SagaStepResult result) {
        SagaState state = sagaStateStore.findById(result.getSagaId());
        
        if (result.isSuccess()) {
            // 步骤成功,执行下一步
            executeNextStep(state);
        } else {
            // 步骤失败,执行补偿
            compensate(state, result.getStep());
        }
    }
    
    private void executeNextStep(SagaState state) {
        SagaStep nextStep = getNextStep(state);
        
        if (nextStep == null) {
            // Saga完成
            state.setStatus(SagaStatus.COMPLETED);
            sagaStateStore.save(state);
            return;
        }
        
        state.setCurrentStep(nextStep.getStepNumber());
        state.setStatus(SagaStatus.PROCESSING);
        sagaStateStore.save(state);
        
        // 发送步骤消息
        kafkaTemplate.send("saga-order", state.getSagaId(), nextStep);
    }
    
    private void compensate(SagaState state, int failedStep) {
        state.setStatus(SagaStatus.COMPENSATING);
        sagaStateStore.save(state);
        
        // 逆向执行已完成步骤的补偿操作
        for (int i = failedStep - 1; i >= 0; i--) {
            SagaStep step = getStep(i);
            kafkaTemplate.send("saga-order-compensate", 
                state.getSagaId(), new CompensateCommand(step));
        }
    }
}

三、协同模式(Choreography)

1. 核心概念

复制代码
┌─────────────────────────────────────────────────────────────────┐
│                       协同模式                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌─────────┐    事件    ┌─────────┐    事件    ┌─────────┐   │
│   │ 服务A   │ ────────▶ │ 服务B   │ ────────▶ │ 服务C   │   │
│   │         │ ◀──────── │         │ ◀──────── │         │   │
│   └─────────┘   命令    └─────────┘   命令    └─────────┘   │
│                                                                  │
│   服务自主决策,通过事件驱动协作                                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2. 事件驱动实现

java 复制代码
// 订单服务 - 发布事件
@Service
public class OrderService {
    
    @Autowired
    private KafkaTemplate kafkaTemplate;
    
    public Order createOrder(OrderRequest request) {
        // 创建订单
        Order order = orderRepository.save(createOrder(request));
        
        // 发布订单创建事件
        kafkaTemplate.send("order-events", order.getId().toString(), 
            new OrderCreatedEvent(order));
        
        return order;
    }
}

// 库存服务 - 订阅事件
@Service
public class InventoryService {
    
    @KafkaListener(topics = "order-events", groupId = "inventory-group")
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 扣减库存
        for (OrderItem item : event.getOrder().getItems()) {
            deductStock(item.getProductId(), item.getQuantity());
        }
        
        // 发布库存扣减成功事件
        kafkaTemplate.send("inventory-events", 
            event.getOrder().getId().toString(),
            new InventoryReservedEvent(event.getOrder()));
    }
}

// 支付服务 - 订阅事件
@Service
public class PaymentService {
    
    @KafkaListener(topics = "inventory-events", groupId = "payment-group")
    public void handleInventoryReserved(InventoryReservedEvent event) {
        // 检查库存是否充足
        if (event.isSuccess()) {
            // 处理支付
            PaymentResult result = processPayment(event.getOrder());
            
            if (result.isSuccess()) {
                // 发布支付成功事件
                kafkaTemplate.send("payment-events",
                    event.getOrder().getId().toString(),
                    new PaymentSucceededEvent(event.getOrder(), result));
            } else {
                // 发布支付失败事件(触发库存回滚)
                kafkaTemplate.send("payment-events",
                    event.getOrder().getId().toString(),
                    new PaymentFailedEvent(event.getOrder(), result.getReason()));
            }
        }
    }
}

// 物流服务 - 订阅事件
@Service
public class LogisticsService {
    
    @KafkaListener(topics = "payment-events", groupId = "logistics-group")
    public void handlePaymentSucceeded(PaymentSucceededEvent event) {
        // 创建物流
        Delivery delivery = createDelivery(event.getOrder());
        
        // 发布发货事件
        kafkaTemplate.send("logistics-events",
            event.getOrder().getId().toString(),
            new OrderShippedEvent(event.getOrder(), delivery));
    }
}

3. 协同模式的优势

java 复制代码
// 服务自治
@Service
public class OrderService {
    
    // 订单服务只需要关注订单相关的业务
    // 不需要知道支付、库存、物流的具体实现
    
    @KafkaListener(topics = "payment-events")
    public void handlePaymentResult(PaymentEvent event) {
        Order order = orderRepository.findById(event.getOrderId());
        
        if (event.isSuccess()) {
            order.setStatus(OrderStatus.PAID);
        } else {
            order.setStatus(OrderStatus.PAYMENT_FAILED);
            order.setFailureReason(event.getReason());
        }
        
        orderRepository.save(order);
        
        // 发布订单状态变更事件
        kafkaTemplate.send("order-events", order.getId().toString(),
            new OrderStatusChangedEvent(order));
    }
}

四、编排vs协同对比

1. 对比表

维度 编排模式 协同模式
中心化 强中心化 去中心化
复杂度 编排器复杂 各服务简单
耦合度 编排器与服务耦合 服务间松耦合
可追踪性 好(编排器控制) 差(需日志聚合)
性能 好(同步调用) 一般(异步消息)
故障处理 编排器统一处理 各服务自行处理
适用场景 复杂业务流程 简单事件流

2. 选择决策

复制代码
选择编排模式:
- 业务流程复杂,需要中心控制
- 需要强一致性
- 需要详细的执行追踪
- 团队习惯面向过程开发

选择协同模式:
- 业务流程简单,事件驱动
- 需要高可用和松耦合
- 团队习惯事件驱动开发
- 已有成熟的消息基础设施

五、混合架构

1. 组合使用

java 复制代码
// 主流程编排,子流程协同
@Service
public class HybridOrderService {
    
    @Autowired
    private KafkaTemplate kafkaTemplate;
    
    // 主流程:编排
    public String createOrder(OrderRequest request) {
        // 1. 编排器验证商品
        List<Product> products = productService.validateProducts(request.getItems());
        
        // 2. 编排器创建订单
        Order order = createOrder(request);
        
        // 3. 子流程:库存扣减(协同)
        kafkaTemplate.send("inventory-commands", 
            order.getId().toString(),
            new ReserveInventoryCommand(order.getItems()));
        
        return order.getId().toString();
    }
}

// 库存子流程:协同
@Service
public class InventoryService {
    
    @KafkaListener(topics = "inventory-commands")
    public void handleReserveCommand(ReserveInventoryCommand command) {
        // 扣减库存
        reserveStock(command.getItems());
        
        // 发布库存预留事件
        kafkaTemplate.send("inventory-events",
            command.getOrderId(),
            new InventoryReservedEvent(command.getOrderId(), true));
    }
}

2. 事件溯源+协同

java 复制代码
// 基于事件的Saga
public class OrderSaga {
    
    @SagaStart
    public void start(OrderRequest request) {
        // 发送创建订单命令
        send("order-service", new CreateOrderCommand(request));
    }
    
    @SagaEvent(topic = "order-created")
    public void onOrderCreated(OrderCreatedEvent event) {
        // 发送扣减库存命令
        send("inventory-service", new ReserveStockCommand(event.getOrder()));
    }
    
    @SagaEvent(topic = "stock-reserved")
    public void onStockReserved(StockReservedEvent event) {
        // 发送支付命令
        send("payment-service", new ProcessPaymentCommand(event.getOrder()));
    }
    
    @SagaEvent(topic = "payment-succeeded")
    public void onPaymentSucceeded(PaymentSucceededEvent event) {
        // 发送发货命令
        send("logistics-service", new CreateDeliveryCommand(event.getOrder()));
        // Saga完成
    }
    
    @SagaEvent(topic = "payment-failed")
    public void onPaymentFailed(PaymentFailedEvent event) {
        // 发送库存回滚命令
        send("inventory-service", new ReleaseStockCommand(event.getOrder()));
        // Saga补偿完成
    }
}

六、异常处理

1. 编排模式异常处理

java 复制代码
@Service
public class OrderOrchestratorWithCompensation {
    
    @Transactional
    public OrderResult createOrder(OrderRequest request) {
        try {
            // 1. 验证商品
            List<Product> products = productService.validateProducts(request.getItems());
            
            // 2. 扣减库存
            inventoryService.deductStock(request.getItems());
            
            // 3. 创建订单
            Order order = orderService.createOrder(request);
            
            // 4. 处理支付
            PaymentResult payment = paymentService.processPayment(order);
            
            if (!payment.isSuccess()) {
                throw new PaymentException("支付失败");
            }
            
            return OrderResult.success(order);
            
        } catch (PaymentException e) {
            // 补偿:回滚库存
            inventoryService.rollbackStock(request.getItems());
            throw e;
            
        } catch (Exception e) {
            // 通用补偿逻辑
            compensate(request);
            throw e;
        }
    }
}

2. 协同模式异常处理

java 复制代码
// 库存服务补偿逻辑
@Service
public class InventoryService {
    
    @KafkaListener(topics = "payment-failed")
    public void handlePaymentFailed(PaymentFailedEvent event) {
        // 回滚库存
        rollbackStock(event.getOrder().getItems());
        
        // 发布库存已回滚事件
        kafkaTemplate.send("inventory-events",
            event.getOrder().getId().toString(),
            new StockRolledBackEvent(event.getOrder()));
    }
    
    @KafkaListener(topics = "order-cancelled")
    public void handleOrderCancelled(OrderCancelledEvent event) {
        // 回滚库存
        rollbackStock(event.getOrder().getItems());
    }
}

七、最佳实践

1. 通信协议选择

java 复制代码
// 同步通信:REST/gRPC
@RestController
public class ProductController {
    
    @GetMapping("/products/{id}")
    public Product getProduct(@PathVariable Long id) {
        return productService.getProduct(id);
    }
}

// 异步通信:消息队列
@Service
public class OrderEventPublisher {
    
    @Autowired
    private KafkaTemplate kafkaTemplate;
    
    public void publishOrderCreated(Order order) {
        kafkaTemplate.send("order-events", order.getId().toString(), 
            new OrderCreatedEvent(order));
    }
}

2. 服务间契约

java 复制代码
// 定义契约
@Contract
public interface OrderServiceContract {
    
    @Endpoint("http://order-service/api")
    interface OrderApi {
        
        @Post("/orders")
        @RequestBody(OrderRequest.class)
        @ResponseBody(OrderResponse.class)
        OrderResponse createOrder(OrderRequest request);
        
        @Get("/orders/{id}")
        @ResponseBody(Order.class)
        Order getOrder(@PathVariable Long id);
    }
}

3. 监控和追踪

java 复制代码
// 分布式追踪
@Component
public class TracingInterceptor {
    
    @Around("@annotation(org.springframework.web.bind.annotation.*)")
    public Object trace(ProceedingJoinPoint point) throws Throwable {
        String traceId = getTraceId();
        String spanId = generateSpanId();
        
        try {
            Object result = point.proceed();
            
            // 记录追踪信息
            tracingService.record(traceId, spanId, 
                point.getSignature().getName(), true, null);
            
            return result;
        } catch (Exception e) {
            tracingService.record(traceId, spanId,
                point.getSignature().getName(), false, e.getMessage());
            throw e;
        }
    }
}

八、总结

微服务通信架构选择:

  • 编排模式:适合复杂业务流程,强中心控制
  • 协同模式:适合简单事件流,去中心化
  • 混合模式:主流程编排,子流程协同
  • Saga:长流程事务处理

最佳实践:

  1. 根据业务复杂度选择模式
  2. 设计好服务间契约
  3. 做好异常处理和补偿
  4. 实现完善的监控追踪

个人观点,仅供参考

相关推荐
LabVIEW开发19 小时前
LabVIEW QMH 队列消息处理架构
架构·labview·labview知识·labview功能·labview程序
rising start21 小时前
二、全面理解MySQL架构
mysql·架构
麦客奥德彪21 小时前
Android Skills
架构·ai编程
姚不倒21 小时前
Go语言进阶:接口、错误处理与并发编程(goroutine/channel/context)
云原生·golang
candyTong21 小时前
Claude Code 的 Edit 工具是怎么工作的
javascript·后端·架构
沪漂阿龙1 天前
面试题详解:智能客服 Agent 系统全栈拆解——Rasa Pro、对话管理、意图识别、GraphRAG、Qwen 与 RAG 优化实战
人工智能·架构
辰海Coding1 天前
MiniSpring框架学习-完成的 IoC 容器
java·spring boot·学习·架构
云边云科技_云网融合1 天前
企业大模型时代的网络架构五层演进:从连接到智能的范式重构
网络·重构·架构
Yunzenn1 天前
字节最新研究cola-DLM第 01 章:语言生成的三次范式之争 —— 从 RNN 到 AR 到扩散
架构·github
她的男孩1 天前
从零搭一个企业后台,为什么我把能力拆成 Starter 和 Plugin
java·后端·架构