5

私はスプリングクラウドを使用して、チケット販売プラットフォームであるマイクロサービスシステムを実装しています。シナリオには、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; 
    } 
} 

いくつかの重要なポイントは以下のとおりです。

  1. fallback機能で、OrderResource.create(order)方法で@HystrixCommandを使用します。
  2. 作成時に何らかのエラーが発生した場合は、インスタンスがOrderResource.create(order)で使用され、フォールバック機能で再度使用されます。この持続性はorderですが、ロールバックされます。しかし、このインスタンスのデータは、まだ実行中をチェックするために使用することができます。
  3. したがって、ステータスが「保留中」、「保留中」、「終了済み」を使用してサービスコールが行われているかどうかを確認します。
  4. ticketCompositeServiceおよびuserCompositeServiceは、偽のクライアントです。 feignクライアントメソッドpayForOrder()の場合は、別の方法payForOrderFallback()があります。
  5. フォールバックメソッドを複数回呼び出すことができるようにする必要があります。
  6. ticketCompositeServiceuserCompositeServiceコールにはtry/catchを追加して、注文は「FAILED」ステータスで保存されることを確認してください。

この解決策はほとんどの場合動作すると思われます。ただし、フォールバック機能では、userCompositeService.payForOrderFallback(payDTO);に何らかのエラーがある場合を除き、次の複合サービスコールは呼び出されません。

もう一つの問題は、それは複雑すぎると思います。

したがって、このシナリオでは、distトランザクションを適切かつ効果的に実装する必要があります。どんな提案や助言も役に立ちます。ありがとう。

+0

Event Sourcing + CQRSのテクニックを試してみるべきです(https://stackoverflow.com/questions/44114755/how-to-do-2-phase-commit-between-two-micro-servicesspring-boot) – sathees

答えて

1

ヒステリックフォールバック内に補正ロジックを書き込むことは、持続性がないため危険です。

このアプローチでは、回復力はありません。データベースからのACID保証は、関係者が関係しているためここでは十分ではなく、Hystrixのフォールバックはあなたのコードに含まれていないものからあなたを守りません。

たとえば、支払い完了後にソリューションが停電(たとえば、停電または単純なkill -9)を経験すると、注文と補償ロジックの両方が失われます。つまり、注文は支払われますが、データベースには表示されません。

より復元力のあるアプローチは、イベントドリブン配信のための一般的なメッセージブローカと、処理ロジックの重複排除を使用して、イベントが停止した後で再配信されたときに、

+0

ありがとう、私はまた、多くのテストコードを書いて、これについて多くを調べる私の最終的な解決策はまた、いくつかのMQとイベント駆動プロセスを使用することです。ありがとう。 – Mavlarn

関連する問題