基於微服務框架Micronaut和Eventuate Tram實現分散式事務的開源案例

banq發表於2019-10-05

Micronaut是一個類似Spring Boot的微服務框架,Eventuate Tram是提供事務性訊息的框架,提供事務發件箱模式,也就是將傳送的訊息首先儲存到帶有主鍵的關聯式資料庫,然後透過訊息系統傳送到接收者,保證近似正好一次的傳遞,該機制類似Apache Kafka事務性訊息,只不過使用該框架可以在RabbitMQ或Akka的訊息系統中實現事務性訊息。
該原始碼案例點選標題進入。該開源作者是《微服務模式》書籍的作者Chris Richardson。
這個應用案例展示了跨微服務實現Saga的機制,以及CQRS模式。
訂單服務是實現CQRS的命令模型,而Order History Service實現CQRS檢視,其訂閱了來自訂單服務發出的領域事件
這個案例的特殊之處在於,它不是基於DDD聚合設計的領域事件,而是直接在微服務中發出領域事件,Order訂單淪為JPA的實體貧血物件了。以下是訂單服務的程式碼:


@Singleton
public class OrderService {

  @Inject
  private DomainEventPublisher domainEventPublisher;

  @PersistenceContext
  private EntityManager entityManager;

  @Transactional
  public Order createOrder(OrderDetails orderDetails) {
    ResultWithEvents<Order> orderWithEvents = Order.createOrder(orderDetails);
    Order order = orderWithEvents.result;
    entityManager.persist(order);
    domainEventPublisher.publish(Order.class, order.getId(), orderWithEvents.events);
    return order;
  }

  public void approveOrder(Long orderId) {
    Order order = Optional.ofNullable(entityManager.find(Order.class, orderId))
            .orElseThrow(() -> new IllegalArgumentException(String.format("order with id %s not found", orderId)));
    order.noteCreditReserved();
    OrderDetails orderDetails = new OrderDetails(order.getOrderDetails().getCustomerId(), new Money(order.getOrderDetails().getOrderTotal().getAmount()));
    domainEventPublisher.publish(Order.class,
            orderId, singletonList(new OrderApprovedEvent(orderDetails)));
  }

  public void rejectOrder(Long orderId) {
    Order order = Optional
            .ofNullable(entityManager.find(Order.class, orderId))
            .orElseThrow(() -> new IllegalArgumentException(String.format("order with id %s not found", orderId)));
    order.noteCreditReservationFailed();
    OrderDetails orderDetails = new OrderDetails(order.getOrderDetails().getCustomerId(), new Money(order.getOrderDetails().getOrderTotal().getAmount()));
    domainEventPublisher.publish(Order.class,
            orderId, singletonList(new OrderRejectedEvent(orderDetails)));
  }
}


批准訂單和拒絕訂單這些應該屬於訂單聚合重要的業務動作被放入了微服務內,微服務成為業務決策者,而不是協調者,正如飯店服務員成為飯店的決策者了。

亮點是透過Saga組成的微服務分散式事務,每個服務內部透過JPA實現ACID,服務之間的訊息透過事務性訊息機制實現正好一次傳遞,透過Saga實現回滾回退補償,以下是其流程,關聯式資料庫在其中實現傳遞訊息的冪等性。


基於微服務框架Micronaut和Eventuate Tram實現分散式事務的開源案例

相關文章