【发布时间】:2017-10-19 07:07:36
【问题描述】:
我正在使用spring cloud来实现我的微服务系统,一个售票平台。场景是,有一个zuul代理,一个eureka注册中心,和3个服务:用户服务、订单服务和票务服务。服务使用 feign 声明式 REST 客户端相互通信。
现在有了买票功能,主要流程如下:
1.订单服务接受创建订单的请求
2. 订单服务创建处于待处理状态的订单实体。
3.订单服务调用用户服务处理用户付款。
4.订单服务调用ticket service更新用户ticket。
5. order service 将 order 实体更新为 FINISHED。
我想使用Hystrix Fallback 来实现事务。例如,如果支付过程完成,但在票的移动过程中发生了一些错误。如何审核用户付款和订单状态。因为用户付款在其他服务中。
以下是我目前的解决方案,我不确定它是否正确。或者有没有其他更好的方法来做到这一点。
首先是 OrderResource:
@RestController
@RequestMapping("/api/order")
public class OrderResource {
@HystrixCommand(fallbackMethod = "createFallback")
@PostMapping(value = "/")
public Order create(@RequestBody Order order) {
return orderService.create(order);
}
private Order createFallback(Order order) {
return orderService.createFallback(order);
}
}
然后是 OrderService:
@Service
public class OrderService {
@Transactional
public Order create(Order order) {
order.setStatus("PENDING");
order = orderRepository.save(order);
UserPayDTO payDTO = new UserPayDTO();
userCompositeService.payForOrder(payDTO);
order.setStatus("PAID");
order = orderRepository.save(order);
ticketCompositeService.moveTickets(ticketIds, currentUserId);
order.setStatus("FINISHED");
order = orderRepository.save(order);
return order;
}
@Transactional
public Order createFallback(Order order) {
// order is the object processed in create(), there is Transaction in create(), so saving order will be rollback,
// but the order instance still exist.
if (order.getId() == null) { // order not saved even.
return null;
}
UserPayDTO payDTO = new UserPayDTO();
try {
if (order.getStatus() == "FINISHED") { // order finished, must be paid and ticket moved
userCompositeService.payForOrderFallback(payDTO);
ticketCompositeService.moveTicketsFallback(getTicketIdList(order.getTicketIds()), currentUserId);
} else if (order.getStatus() == "PAID") { // is paid, but not sure whether has error during ticket movement.
userCompositeService.payForOrderFallback(payDTO);
ticketCompositeService.moveTicketsFallback(getTicketIdList(order.getTicketIds()), currentUserId);
} else if (order.getStatus() == "PENDING") { // maybe have error during payment.
userCompositeService.payForOrderFallback(payDTO);
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
order.setStatus("FAILED");
orderRepository.save(order); // order saving is rollbacked during create(), I save it here to trace the failed orders.
return order;
}
}
这里的一些关键点是:
- 在
OrderResource.create(order)方法中使用@HystrixCommand,带有fallback函数。 - 如果创建过程中出现错误,
OrderResource.create(order)中使用的order实例将在回退功能中再次使用。虽然这个order的持久性会被回滚。但是这个实例中的数据仍然可以用来检查运行情况。 - 所以我使用状态:'PENDING'、'PAID'、'FINISHED'来检查是否进行了某些服务调用。
-
ticketCompositeService和userCompositeService是假客户。对于 feign 客户端方法payForOrder(),还有另一种方法payForOrderFallback()用于回退。 - 我需要确保可以多次调用回退方法。
- 我为
ticketCompositeService和userCompositeService调用添加了try/catch,以确保订单将以“失败”状态保存。
似乎这个解决方案大部分时间都可以工作。除此之外,在fallback函数中,如果userCompositeService.payForOrderFallback(payDTO);有错误,那么下面的复合服务调用将不会被调用。
而且,另一个问题是,我认为它太复杂了。
那么,对于这种情况,我应该如何正确有效地实现 dist 事务。任何建议或意见都会有所帮助。谢谢。
【问题讨论】:
-
你应该试试 Event Sourcing + CQRS 技术link
标签: spring-cloud microservices distributed-transactions hystrix spring-cloud-netflix