私はスプリングクラウドを使用して、チケット販売プラットフォームであるマイクロサービスシステムを実装しています。シナリオには、zuulプロキシ、ユーレカレジストリ、および3つのサービス、ユーザサービス、オーダーサービス、チケットサービスがあります。サービスは宣言型のRESTクライアントを使用して相互に通信します。Spring Cloudアーキテクトに基づくhystrixフォールバックによる分散トランザクションの実装方法
今すぐチケットを購入する機能があり、メインプロセスは以下の通りです:
1.注文サービスオーダー
2.注文サービスを作成するための要求が保留状態とOrderエンティティを作成して受け入れます。
3.注文サービスコールユーザーサービスは、ユーザー支払いを処理します。
4.ユーザーチケットを更新するためのサービスコールチケットサービスを注文します。
5.注文サービスは注文実体を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;
}
}
いくつかの重要なポイントは以下のとおりです。
fallback
機能で、OrderResource.create(order)
方法で@HystrixCommand
を使用します。- 作成時に何らかのエラーが発生した場合は、インスタンスが
OrderResource.create(order)
で使用され、フォールバック機能で再度使用されます。この持続性はorder
ですが、ロールバックされます。しかし、このインスタンスのデータは、まだ実行中をチェックするために使用することができます。 - したがって、ステータスが「保留中」、「保留中」、「終了済み」を使用してサービスコールが行われているかどうかを確認します。
ticketCompositeService
およびuserCompositeService
は、偽のクライアントです。 feignクライアントメソッドpayForOrder()
の場合は、別の方法payForOrderFallback()
があります。- フォールバックメソッドを複数回呼び出すことができるようにする必要があります。
ticketCompositeService
とuserCompositeService
コールにはtry/catch
を追加して、注文は「FAILED」ステータスで保存されることを確認してください。
この解決策はほとんどの場合動作すると思われます。ただし、フォールバック機能では、userCompositeService.payForOrderFallback(payDTO);
に何らかのエラーがある場合を除き、次の複合サービスコールは呼び出されません。
もう一つの問題は、それは複雑すぎると思います。
したがって、このシナリオでは、distトランザクションを適切かつ効果的に実装する必要があります。どんな提案や助言も役に立ちます。ありがとう。
Event Sourcing + CQRSのテクニックを試してみるべきです(https://stackoverflow.com/questions/44114755/how-to-do-2-phase-commit-between-two-micro-servicesspring-boot) – sathees