DDD-008:DDD 与微服务架构

DDD-008:DDD 与微服务架构

8.1 微服务架构概述

8.1.1 微服务定义

【原理】
微服务架构是一种架构风格,将单一应用程序划分成一组小的服务,每个服务运行在独立的进程中,服务间通过轻量级通信机制(通常是HTTP资源API)进行协作。

核心特征:

  • 服务自治:每个服务独立开发、测试、部署
  • 去中心化:数据管理去中心化,每个服务管理自己的数据库
  • 轻量通信:服务间通过REST、gRPC或消息队列通信
  • 按业务能力划分:服务边界基于业务能力而非技术层

【历史架构问题】
传统单体架构:

// ❌ 单体架构:所有功能在一个应用中
@RestController
public class MonolithicController {
    @Autowired private UserRepository userRepository;
    @Autowired private OrderRepository orderRepository;
    @Autowired private ProductRepository productRepository;
    @Autowired private PaymentRepository paymentRepository;
    @Autowired private ShippingRepository shippingRepository;

    @PostMapping("/orders")
    public Order createOrder(@RequestBody OrderDTO dto) {
        // 用户验证
        User user = userRepository.findById(dto.getUserId());
        // 商品查询
        Product product = productRepository.findById(dto.getProductId());
        // 订单创建
        Order order = orderRepository.save(new Order(user, product));
        // 支付处理
        paymentRepository.save(new Payment(order));
        // 物流创建
        shippingRepository.save(new Shipping(order));
        return order;
    }
}

存在问题:

  1. 代码耦合:所有模块在同一代码库,相互依赖
  2. 部署风险:修改一行代码需要重新部署整个应用
  3. 技术栈绑定:所有模块必须使用相同技术栈
  4. 扩展受限:无法按需扩展单个功能模块
  5. 团队协作困难:多人修改同一代码库,冲突频繁

【DDD 如何解决】
基于限界上下文的微服务拆分:

// ✅ 订单服务:独立部署
@RestController
@RequestMapping("/orders")
public class OrderServiceController {
    private final OrderApplicationService orderService;
    private final EventPublisher eventPublisher;

    @PostMapping
    public OrderDTO createOrder(@RequestBody CreateOrderCommand cmd) {
        Order order = orderService.createOrder(cmd);
        eventPublisher.publish(new OrderCreatedEvent(order.getId()));
        return OrderDTO.from(order);
    }
}

// ✅ 支付服务:独立部署,通过事件驱动
@Component
public class PaymentEventHandler {
    @EventListener
    public void handle(OrderCreatedEvent event) {
        // 异步处理支付
    }
}

【设计优势】

维度单体架构微服务架构(DDD指导)
部署整体部署独立部署
扩展整体扩展按需扩展
技术栈统一多样化
团队协作集中式分布式自治
故障影响全局影响局部影响

8.1.2 微服务优势与挑战

优势:

  1. 独立部署:服务独立部署,不影响其他服务
  2. 技术多样性:不同服务可选择最适合的技术栈
  3. 弹性扩展:按需扩展单个服务,资源利用率高
  4. 团队自治:不同团队负责不同服务,并行开发
  5. 故障隔离:单个服务故障不影响整体系统

挑战:

  1. 分布式复杂性:网络延迟、部分失败、分布式事务
  2. 服务发现与治理:服务注册、负载均衡、熔断降级
  3. 数据一致性:跨服务事务、最终一致性保证
  4. 运维复杂性:监控、日志、链路追踪
  5. 测试复杂性:集成测试、端到端测试

8.1.3 与单体架构的对比

维度单体架构微服务架构
部署整体部署独立部署
扩展整体扩展按需扩展
技术栈统一多样化
团队协作集中式分布式自治
复杂性代码复杂运维复杂
故障影响全局影响局部影响
启动时间较长较短
开发调试简单复杂

8.2 限界上下文与微服务的映射

8.2.1 理想情况:一对一映射

【原理】
DDD的限界上下文与微服务存在天然的映射关系。理想情况下,一个限界上下文对应一个微服务。

// 限界上下文与微服务一一对应
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   订单上下文     │    │   商品上下文     │    │   用户上下文     │
│ OrderContext    │    │ ProductContext  │    │  UserContext    │
└────────┬────────┘    └────────┬────────┘    └────────┬────────┘
         │                      │                      │
         ▼                      ▼                      ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   订单服务       │    │   商品服务       │    │   用户服务       │
│  Order Service  │    │ Product Service │    │  User Service   │
└─────────────────┘    └─────────────────┘    └─────────────────┘

【设计优势】

  • 清晰的边界:每个服务职责明确
  • 独立演进:服务可独立迭代
  • 团队对齐:一个团队负责一个上下文

8.2.2 现实考量

【历史架构问题】
实际项目中,简单的一对一映射往往不够:

// ❌ 过度拆分问题:小功能单独成服务
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  地址服务     │  │  手机号服务   │  │  邮箱服务     │
│ AddressSvc   │  │  PhoneSvc    │  │  EmailSvc    │
└──────────────┘  └──────────────┘  └──────────────┘
// 问题:服务数量过多,运维负担重,调用链过长

现实考量因素:

  1. 团队规模

    • 小团队:合并多个上下文到一个服务
    • 大团队:一个上下文一个服务,甚至多个服务
  2. 性能要求

    • 高频调用:考虑合并到同一服务减少网络开销
    • 低频调用:可独立部署
  3. 部署频率

    • 高频变更:独立服务,快速迭代
    • 稳定模块:可合并到其他服务
  4. 数据依赖

    • 强依赖:考虑合并
    • 弱依赖:可独立

【DDD 如何解决】
灵活的映射策略:

// ✅ 合理的服务划分
┌─────────────────────────────────────────┐
│         用户上下文 (User Context)         │
│  ┌────────┐ ┌────────┐ ┌────────┐       │
│  │ 用户    │ │ 地址   │ │ 认证   │       │
│  │User    │ │Address │ │Auth    │       │
│  └────────┘ └────────┘ └────────┘       │
└─────────────────┬───────────────────────┘
                  ▼
        ┌─────────────────┐
        │   用户服务       │
        │  User Service   │
        │ (合并部署)       │
        └─────────────────┘

// 订单上下文独立部署(高频变更)
┌─────────────────┐
│   订单上下文     │
└────────┬────────┘
         ▼
┌─────────────────┐
│   订单服务       │
│  Order Service  │
│  (独立部署)      │
└─────────────────┘

8.2.3 演进策略

从单体到微服务的演进:

// 阶段1:单体模块化
┌─────────────────────────────────────────────┐
│              Monolithic Application          │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐       │
│  │ Order   │ │ Product │ │ User    │       │
│  │ Module  │ │ Module  │ │ Module  │       │
│  └─────────┘ └─────────┘ └─────────┘       │
└─────────────────────────────────────────────┘

// 阶段2:模块边界清晰化(DDD限界上下文)
┌─────────────────────────────────────────────┐
│         Modular Monolith (DDD)               │
│  ┌─────────────┐ ┌─────────────┐           │
│  │OrderContext │ │ProductContext│           │
│  │ (Bounded)   │ │ (Bounded)   │           │
│  └─────────────┘ └─────────────┘           │
└─────────────────────────────────────────────┘

// 阶段3:提取高频变更的上下文为微服务
┌──────────────────────┐    ┌──────────────┐
│  Modular Monolith    │    │ Order Service │
│ ┌────┐ ┌────┐       │    │ (独立部署)    │
│ │User│ │Pay │       │◄──►└──────────────┘
│ └────┘ └────┘       │
└──────────────────────┘

// 阶段4:完整微服务架构
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ Order  │ │ Product│ │  User  │ │Payment │
│Service │ │Service │ │Service │ │Service │
└────────┘ └────────┘ └────────┘ └────────┘

8.3 微服务的边界划分原则

8.3.1 业务边界优先

【原理】
微服务的划分应基于业务能力,而非技术分层。

【历史架构问题】
按技术层拆分:

// ❌ 错误:按技术层拆分
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│  Web Service│ │API Service  │ │ Data Service │
│  (前端)     │ │ (接口层)     │ │ (数据层)     │
└─────────────┘ └─────────────┘ └─────────────┘

// 问题:
// 1. 所有业务变更都需要修改多个服务
// 2. 跨服务事务复杂
// 3. 服务职责不清晰

【DDD 如何解决】
按业务能力拆分:

// ✅ 正确:按业务能力拆分
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ OrderService│ │ProductSvc   │ │PaymentService│
│ (订单业务)   │ │(商品业务)    │ │ (支付业务)   │
└─────────────┘ └─────────────┘ └─────────────┘

// 优势:
// 1. 业务变更只需修改一个服务
// 2. 服务职责清晰
// 3. 团队自治

8.3.2 数据边界

【原理】
每个微服务应该有自己独立的数据库,避免数据层耦合。

【历史架构问题】
共享数据库:

// ❌ 共享数据库:强耦合
┌─────────────┐ ┌─────────────┐
│ OrderService│ │ProductService│
└──────┬──────┘ └──────┬──────┘
       │               │
       └───────┬───────┘
               ▼
       ┌───────────────┐
       │  Shared DB    │
       │ ┌────┐┌────┐  │
       │ │order││product│ │
       │ └────┘└────┘  │
       └───────────────┘

// 问题:
// 1. 表结构变更影响多个服务
// 2. 数据库成为性能瓶颈
// 3. 无法独立扩展

【DDD 如何解决】
数据库独占:

// ✅ 独占数据库:解耦
┌─────────────┐       ┌─────────────┐
│ OrderService│       │ProductService│
└──────┬──────┘       └──────┬──────┘
       │                     │
       ▼                     ▼
┌─────────────┐       ┌─────────────┐
│  Order DB   │       │ Product DB  │
│ (独立)      │       │ (独立)      │
└─────────────┘       └─────────────┘

// 需要数据时通过API调用
ProductDTO product = productClient.getProduct(productId);

8.3.3 团队边界(康威定律)

【原理】
康威定律:系统架构反映组织的沟通结构。

“设计系统的组织,其产生的设计等同于组织间的沟通结构。” —— Melvin Conway

实践建议:

  • 一个团队负责一个或多个服务
  • 服务边界与团队边界对齐
  • 避免跨团队频繁协作的服务
// 团队与服务对齐
┌─────────────────────────────────────────┐
│           订单团队                        │
│  ┌─────────────┐ ┌─────────────┐       │
│  │ OrderService│ │CartService  │       │
│  └─────────────┘ └─────────────┘       │
└─────────────────────────────────────────┘

┌─────────────────────────────────────────┐
│           商品团队                        │
│  ┌─────────────┐ ┌─────────────┐       │
│  │ProductService│ │InventorySvc│       │
│  └─────────────┘ └─────────────┘       │
└─────────────────────────────────────────┘

8.3.4 技术边界(谨慎使用)

【历史架构问题】
过度按技术拆分:

// ❌ 错误:按技术组件拆分
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│  Auth Svc    │ │  Log Svc     │ │  Cache Svc   │
│ (认证服务)   │ │ (日志服务)   │ │ (缓存服务)   │
└──────────────┘ └──────────────┘ └──────────────┘

// 问题:这些是技术关注点,不是业务能力

【DDD 如何解决】
技术能力作为支撑,嵌入业务服务:

// ✅ 技术能力作为基础设施
┌─────────────────────────────────────────┐
│            Order Service                 │
│  ┌────────┐ ┌────────┐ ┌────────┐     │
│  │ Auth   │ │ Log    │ │ Cache  │     │
│  │(内部)  │ │(内部)  │ │(内部)  │     │
│  └────────┘ └────────┘ └────────┘     │
└─────────────────────────────────────────┘

8.4 微服务间的通信模式

8.4.1 同步通信

REST API

// Feign 声明式调用
@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/api/products/{id}")
    ProductDTO getProduct(@PathVariable Long id);

    @PostMapping("/api/products/{id}/reserve")
    void reserveStock(@PathVariable Long id, @RequestParam int quantity);
}

// 订单服务调用商品服务
@Service
public class OrderApplicationService {
    private final ProductClient productClient;

    public Order createOrder(CreateOrderCommand cmd) {
        // 同步调用商品服务
        ProductDTO product = productClient.getProduct(cmd.getProductId());

        // 检查库存
        if (product.getStock() < cmd.getQuantity()) {
            throw new InsufficientStockException();
        }

        // 预留库存
        productClient.reserveStock(cmd.getProductId(), cmd.getQuantity());

        // 创建订单...
    }
}

gRPC

// product.proto
syntax = "proto3";
package com.example.product;

service ProductService {
    rpc GetProduct(GetProductRequest) returns (ProductResponse);
    rpc ReserveStock(ReserveStockRequest) returns (ReserveStockResponse);
}

message GetProductRequest {
    int64 id = 1;
}

message ProductResponse {
    int64 id = 1;
    string name = 2;
    int32 stock = 3;
}
// gRPC 客户端
@Service
public class ProductGrpcClient {
    private final ProductServiceGrpc.ProductServiceBlockingStub stub;

    public ProductDTO getProduct(Long id) {
        GetProductRequest request = GetProductRequest.newBuilder()
            .setId(id)
            .build();

        ProductResponse response = stub.getProduct(request);
        return new ProductDTO(response.getId(), response.getName(), response.getStock());
    }
}

适用场景:

  • 需要实时响应的场景
  • 查询类操作
  • 简单的业务流程

问题:

  • 调用链长时延迟累积
  • 服务提供方故障影响调用方
  • 紧耦合

8.4.2 异步通信

消息队列

// 订单服务发布事件
@Service
public class OrderApplicationService {
    private final OrderRepository orderRepository;
    private final MessageQueue messageQueue;

    @Transactional
    public Order createOrder(CreateOrderCommand cmd) {
        Order order = Order.create(cmd);
        orderRepository.save(order);

        // 发布订单创建事件
        OrderCreatedEvent event = new OrderCreatedEvent(
            order.getId(),
            order.getUserId(),
            order.getTotalAmount()
        );
        messageQueue.publish("order.created", event);

        return order;
    }
}

// 库存服务订阅事件
@Component
public class InventoryEventHandler {
    @RabbitListener(queues = "order.created")
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 异步扣减库存
        inventoryService.reserveStock(event.getOrderId());
    }
}

// 支付服务订阅事件
@Component
public class PaymentEventHandler {
    @RabbitListener(queues = "order.created")
    public void handleOrderCreated(OrderCreatedEvent event) {
        // 异步创建支付单
        paymentService.createPayment(event.getOrderId(), event.getAmount());
    }
}

事件驱动架构

// 领域事件定义
public abstract class DomainEvent {
    private final LocalDateTime occurredOn;
    private final String eventId;

    protected DomainEvent() {
        this.occurredOn = LocalDateTime.now();
        this.eventId = UUID.randomUUID().toString();
    }
}

// 订单创建事件
public class OrderCreatedEvent extends DomainEvent {
    private final Long orderId;
    private final Long userId;
    private final BigDecimal totalAmount;
    private final List<OrderItemDTO> items;
}

// 事件总线
@Service
public class EventBus {
    private final ApplicationEventPublisher publisher;

    public void publish(DomainEvent event) {
        publisher.publishEvent(event);

        // 同时发送到消息队列(跨服务)
        messageQueue.publish(event.getClass().getSimpleName(), event);
    }
}

适用场景:

  • 不需要实时响应的场景
  • 解耦服务依赖
  • 削峰填谷
  • 最终一致性场景

优势:

  • 服务解耦
  • 故障隔离
  • 异步处理提高响应速度
  • 天然支持重试

8.5 避免分布式单体

8.5.1 什么是分布式单体?

【原理】
分布式单体(Distributed Monolith):虽然拆分成了多个服务,但服务间紧密耦合,每次变更都需要修改多个服务,部署时需要协调多个服务。

【历史架构问题】

// ❌ 分布式单体的典型特征

// 1. 跨服务的"大事务"
@Service
public class OrderService {
    @Transactional  // 这个事务根本不起作用!
    public void createOrder(OrderDTO dto) {
        orderRepository.save(order);
        productService.decreaseStock(productId, quantity);  // 跨服务
        couponService.useCoupon(couponId);                   // 跨服务
        pointsService.addPoints(userId, amount);             // 跨服务
        notificationService.sendSMS(userId, "订单创建成功");  // 跨服务
    }
}

// 2. 服务间的循环依赖
OrderService -> ProductService -> InventoryService -> OrderService

// 3. 共享数据库
OrderService ──┐
ProductService ─┼──► Shared Database
UserService ────┘

// 4. 每次发布需要协调多个服务

常见表现:

  1. 变更传播:修改一个功能需要改动多个服务
  2. 部署依赖:发布时必须按特定顺序部署多个服务
  3. 测试困难:修改一个服务需要测试所有相关服务
  4. 故障扩散:一个服务故障导致整个系统不可用

8.5.2 如何避免分布式单体?

【DDD 如何解决】

1. 正确的限界上下文划分

// ✅ 高内聚、低耦合的上下文划分

// 订单上下文:包含订单、购物车、订单项
// 所有订单相关的业务逻辑都在这个上下文内
public class Order extends AggregateRoot<OrderId> {
    private OrderId id;
    private CustomerId customerId;
    private OrderStatus status;
    private List<OrderItem> items;
    private Money totalAmount;

    // 业务逻辑封装在聚合内
    public void addItem(ProductId productId, Money price, int quantity) {
        // 验证
        if (this.status != OrderStatus.DRAFT) {
            throw new IllegalStateException("只能修改草稿订单");
        }

        // 添加商品
        OrderItem item = new OrderItem(productId, price, quantity);
        this.items.add(item);

        // 重新计算总额
        this.totalAmount = calculateTotal();
    }

    public void submit() {
        if (items.isEmpty()) {
            throw new IllegalStateException("订单不能为空");
        }
        this.status = OrderStatus.SUBMITTED;
        // 发布领域事件,而不是直接调用其他服务
        registerEvent(new OrderSubmittedEvent(this.id, this.totalAmount));
    }
}

2. 使用领域事件解耦

// ✅ 事件驱动:服务解耦

// 订单服务只关心订单提交,不关心后续流程
public class OrderApplicationService {
    public void submitOrder(OrderId orderId) {
        Order order = orderRepository.findById(orderId);
        order.submit();
        orderRepository.save(order);

        // 发布事件,不调用其他服务
        eventPublisher.publish(new OrderSubmittedEvent(order));
    }
}

// 库存服务独立响应
@Component
public class InventoryEventHandler {
    @EventListener
    @Async
    public void handle(OrderSubmittedEvent event) {
        inventoryService.reserveStock(event.getItems());
    }
}

// 支付服务独立响应
@Component
public class PaymentEventHandler {
    @EventListener
    @Async
    public void handle(OrderSubmittedEvent event) {
        paymentService.createPayment(event.getOrderId(), event.getAmount());
    }
}

3. 每个服务独占数据库

// ✅ 数据库独占
@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }

    @Bean
    @Primary
    public DataSource orderDataSource() {
        // 订单服务自己的数据库
        return DataSourceBuilder.create()
            .url("jdbc:mysql://order-db:3306/orders")
            .build();
    }
}

// 需要商品信息时,通过API获取,而不是直接查询商品库
@Service
public class OrderApplicationService {
    private final ProductClient productClient;

    public ProductInfo getProductInfo(ProductId productId) {
        // 调用商品服务API
        return productClient.getProduct(productId);
    }
}

4. API版本管理

// ✅ 稳定的API契约

// 商品服务API(版本化)
@RestController
@RequestMapping("/api/v1/products")
public class ProductController {
    @GetMapping("/{id}")
    public ProductDTO getProduct(@PathVariable Long id) {
        // 稳定的API契约
    }
}

// 如果需要变更,创建新版本
@RestController
@RequestMapping("/api/v2/products")
public class ProductV2Controller {
    @GetMapping("/{id}")
    public ProductV2DTO getProduct(@PathVariable Long id) {
        // 新版本的API
    }
}

5. 使用防腐层

// ✅ 防腐层隔离外部服务变更

// 适配器接口
public interface ProductAdapter {
    ProductInfo getProduct(ProductId productId);
    void reserveStock(ProductId productId, int quantity);
}

// 实现:调用商品服务
@Component
public class ProductAdapterImpl implements ProductAdapter {
    private final ProductClient productClient;

    @Override
    public ProductInfo getProduct(ProductId productId) {
        ProductDTO dto = productClient.getProduct(productId.getValue());
        // 转换为内部模型
        return new ProductInfo(
            new ProductId(dto.getId()),
            dto.getName(),
            new Money(dto.getPrice())
        );
    }

    @Override
    public void reserveStock(ProductId productId, int quantity) {
        productClient.reserveStock(productId.getValue(), quantity);
    }
}

// 订单服务使用防腐层,而非直接调用
@Service
public class OrderApplicationService {
    private final ProductAdapter productAdapter;  // 依赖接口

    public Order createOrder(CreateOrderCommand cmd) {
        ProductInfo product = productAdapter.getProduct(cmd.getProductId());
        // ...
    }
}

8.6 微服务与 DDD 的最佳实践

8.6.1 服务拆分策略

拆分原则:

  1. 从限界上下文出发
  2. 考虑团队规模和能力
  3. 考虑性能和可用性要求
  4. 渐进式拆分

拆分决策流程:

// 决策流程
public class ServiceSplitDecision {

    public boolean shouldSplit(BoundedContext context) {
        // 1. 变更频率分析
        if (getChangeFrequency(context) > threshold) {
            return true;
        }

        // 2. 团队规模分析
        if (getTeamSize(context) > 8) {
            return true;
        }

        // 3. 性能要求分析
        if (getQPS(context) > 10000) {
            return true;
        }

        // 4. 业务独立性分析
        if (isIndependentBusiness(context)) {
            return true;
        }

        return false;
    }
}

8.6.2 数据一致性保证

最终一致性方案:

// ✅ 基于事件驱动的最终一致性

// 本地消息表方案
@Service
public class OrderApplicationService {
    private final OrderRepository orderRepository;
    private final OutboxRepository outboxRepository;

    @Transactional
    public void submitOrder(OrderId orderId) {
        // 1. 业务操作
        Order order = orderRepository.findById(orderId);
        order.submit();
        orderRepository.save(order);

        // 2. 写入消息表(同一事务)
        OutboxMessage message = new OutboxMessage(
            "order.submitted",
            new OrderSubmittedEvent(order)
        );
        outboxRepository.save(message);
    }
}

// 后台任务轮询发送消息
@Scheduled(fixedRate = 1000)
public void processOutbox() {
    List<OutboxMessage> messages = outboxRepository.findUnsent();
    for (OutboxMessage msg : messages) {
        messageQueue.publish(msg.getTopic(), msg.getPayload());
        msg.markAsSent();
        outboxRepository.save(msg);
    }
}

// 消费者幂等处理
@Component
public class InventoryEventHandler {
    @RabbitListener(queues = "order.submitted")
    public void handle(OrderSubmittedEvent event) {
        // 幂等性检查
        if (inventoryRepository.existsByOrderId(event.getOrderId())) {
            return;  // 已处理
        }

        // 业务处理
        inventoryService.reserveStock(event.getItems());

        // 记录已处理
        inventoryRepository.saveProcessedOrder(event.getOrderId());
    }
}

Saga模式:

// 编排式Saga
@Service
public class OrderSagaOrchestrator {

    public void executeCreateOrderSaga(CreateOrderCommand cmd) {
        // 步骤1:创建订单
        Order order = orderService.createOrder(cmd);

        try {
            // 步骤2:预留库存
            inventoryService.reserveStock(order.getId());

            // 步骤3:创建支付
            paymentService.createPayment(order.getId());

            // 步骤4:确认订单
            orderService.confirmOrder(order.getId());

        } catch (Exception e) {
            // 补偿操作
            orderService.cancelOrder(order.getId());
            inventoryService.releaseStock(order.getId());
            paymentService.cancelPayment(order.getId());
        }
    }
}

// 协同式Saga(基于事件)
public class OrderSagaCoordinator {

    @EventHandler
    public void handle(OrderSubmittedEvent event) {
        inventoryService.reserveStock(event.getOrderId());
    }

    @EventHandler
    public void handle(StockReservedEvent event) {
        paymentService.createPayment(event.getOrderId());
    }

    @EventHandler
    public void handle(PaymentCreatedEvent event) {
        orderService.confirmOrder(event.getOrderId());
    }

    @EventHandler
    public void handle(PaymentFailedEvent event) {
        inventoryService.releaseStock(event.getOrderId());
        orderService.cancelOrder(event.getOrderId());
    }
}

8.6.3 服务治理

服务注册与发现:

// Spring Cloud 服务注册
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}

// Feign 客户端(自动服务发现)
@FeignClient(name = "product-service")
public interface ProductClient {
    @GetMapping("/api/products/{id}")
    ProductDTO getProduct(@PathVariable Long id);
}

熔断降级:

// Resilience4j 熔断配置
@Configuration
public class CircuitBreakerConfig {

    @Bean
    public CircuitBreaker productCircuitBreaker() {
        CircuitBreakerConfig config = CircuitBreakerConfig.custom()
            .failureRateThreshold(50)              // 失败率阈值50%
            .waitDurationInOpenState(Duration.ofSeconds(30))  // 开启状态等待时间
            .slidingWindowSize(10)                 // 滑动窗口大小
            .build();

        return CircuitBreaker.of("productService", config);
    }
}

// 使用熔断
@Service
public class OrderApplicationService {
    private final ProductClient productClient;
    private final CircuitBreaker circuitBreaker;

    public ProductInfo getProductWithFallback(Long productId) {
        return circuitBreaker.executeSupplier(() ->
            productClient.getProduct(productId)
        );
    }

    // 降级方法
    public ProductInfo getProductFallback(Long productId) {
        return new ProductInfo(productId, "默认商品", BigDecimal.ZERO);
    }
}

限流:

// Resilience4j 限流
@RateLimiter(name = "productService", fallbackMethod = "getProductFallback")
public ProductDTO getProduct(Long productId) {
    return productClient.getProduct(productId);
}

8.7 总结与实践建议

核心要点回顾

  1. 限界上下文是微服务划分的天然边界

    • 先做DDD战略设计,再考虑服务拆分
    • 限界上下文与服务不是简单的一一对应
  2. 避免分布式单体

    • 服务间通过事件解耦,而非直接调用
    • 每个服务独占数据库
    • 使用防腐层隔离外部依赖
  3. 合理选择通信模式

    • 查询类操作:同步API
    • 命令类操作:异步消息
    • 关键路径:考虑同步+补偿
  4. 数据一致性保证

    • 接受最终一致性
    • 使用Saga模式处理跨服务事务
    • 幂等性设计
  5. 渐进式演进

    • 从模块化单体开始
    • 提取高频变更的上下文为服务
    • 逐步演进到微服务

实践建议

起步阶段:

  • 先实现模块化单体(DDD限界上下文)
  • 建立清晰的模块边界
  • 练习事件驱动架构

服务拆分时机:

  • 团队规模增长,协作成本增加
  • 部署频率提高,发布冲突频繁
  • 某个模块性能要求高,需要独立扩展

拆分原则:

  • 一次只拆一个上下文
  • 优先拆分变更频率高的上下文
  • 保证每个服务的独立性

思考题

基础题:

  1. 什么是分布式单体?它有哪些特征?
  2. 限界上下文与微服务是什么关系?
  3. 微服务间通信有哪些模式?各有什么优缺点?

进阶题:

  1. 如何判断一个限界上下文是否应该独立为微服务?
  2. 跨服务的业务事务如何保证一致性?
  3. 如何设计防腐层来隔离外部服务?

实战题:

  1. 设计一个电商系统的服务拆分方案,说明每个服务的职责和边界。
  2. 实现一个基于本地消息表的最终一致性方案。
  3. 为订单服务设计熔断降级策略。

章节关联

  • 前置知识:DDD-004 领域、子域与限界上下文、DDD-006 上下文映射
  • 相关章节:DDD-007 领域事件、DDD-017 六边形架构、DDD-024 事务管理与一致性保证
  • 下一章:DDD-009 实体(Entity)- 深入战术设计

关键词: 微服务、服务拆分、分布式单体、服务通信、限界上下文映射、事件驱动、最终一致性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值