API Gateway(REST)+イベント駆動型マイクロサービス


16

API Gatewayパターンに従ってREST APIを介して機能を公開するマイクロサービスがたくさんあります。これらのマイクロサービスはSpring Bootアプリケーションなので、Spring AMQPを使用して、これらのマイクロサービス間でRPCスタイルの同期通信を実現しています。これまでのところ物事は順調に進んでいます。ただし、イベント駆動型のマイクロサービスアーキテクチャについて詳しく読んで、Spring Cloud Streamなどのプロジェクトを見ると、RPC同期アプローチで間違った方法で物事をしている可能性があると確信するようになります(特に、これをスケーリングする必要があるため)クライアントアプリケーションからの1秒あたり数百または数千のリクエストに応答するため)。

イベント駆動型アーキテクチャの背後にあるポイントを理解しています。私がよく理解していないのは、すべての要求に対する応答を期待するモデル(REST)の後ろに座っているときに、そのようなパターンを実際に使用する方法です。たとえば、APIゲートウェイをマイクロサービスとして使用し、ユーザーを保存および管理する別のマイクロサービスがあるGET /users/1場合、純粋にイベント駆動型のようにモデル化するにはどうすればよいですか?

回答:


9

私の後に繰り返して:

RESTおよび非同期イベントは代替ではありません。それらは完全に直交しています。

どちらか一方、または両方を持つか、どちらも持たないことができます。これらは、まったく異なる問題領域に対応するまったく異なるツールです。実際、汎用の要求/応答通信は、非同期でイベント駆動型であり、フォールトトレラントであることが絶対に可能です


些細な例として、AMQPプロトコルはTCP接続を介してメッセージを送信します。TCPでは、すべてのパケットは受信者によって確認される必要があります。パケットの送信者がそのパケットのACKを受信しない場合、ACKされるまで、またはアプリケーション層が「あきらめて」接続を放棄するまで、そのパケットを再送信し続けます。すべての「パケット送信要求」に付随する「パケット確認応答」が必要であり、応答に失敗すると接続全体が失敗するため、これは明らかに非フォールトトレラントな要求応答モデルです。非同期フォールトトレラントメッセージング用に標準化され広く採用されているプロトコルであるAMQPは、TCPを介して通信されます!何が得られますか?

ここで重要な概念は、スケーラブルで疎結合のフォールトトレラントメッセージングが、送信方法ではなく、送信するメッセージによって定義されるということです。言い換えると、疎結合はアプリケーション層で定義されます

RESTful HTTPと直接通信するか、AMQPメッセージブローカーと間接的に通信する2つのパーティを見てみましょう。パーティーAがパーティーBにJPEGイメージをアップロードし、パーティーBがイメージをシャープ、圧縮、またはその他の方法で強化したいとします。パーティAは処理された画像をすぐに必要としませんが、将来の使用と検索のためにそれへの参照を必要とします。RESTで使用できる方法の1つを次に示します。

  • パーティAは、HTTP POST要求メッセージをパーティBに送信します。Content-Type: image/jpeg
  • パーティBは、パーティAが待機している間にイメージを処理します(大きい場合は長時間)。
  • パーティB は、処理されたイメージにリンク201 CreatedするContent-Location: <url>ヘッダーとともにHTTP 応答メッセージをパーティAに送信します
  • パーティAは、処理された画像への参照を持っているため、作業が完了したと見なします。
  • 将来、パーティーAが処理済みの画像を必要とする場合、以前のContent-Locationヘッダーからのリンクを使用して取得します

201 Created応答コードは、その要求が成功しただけでなく、クライアントに伝え、それはまた、新しいリソースを作成しました。201応答では、Content-Locationヘッダーは作成されたリソースへのリンクです。これは、RFC 7231セクション6.3.2および3.1.4.2で指定されています。

次に、AMQP上で仮想RPCプロトコル上でこの相互作用がどのように機能するかを見てみましょう。

  • パーティAは、AMQPメッセージブローカー(メッセンジャーと呼びます)に画像とメッセージを処理するためにパーティBにルーティングする指示を含むメッセージを送信し、画像の何らかのアドレスでパーティAに応答します
  • パーティーAが待機し、おそらく他のことを行う
  • メッセンジャーはパーティーAの元のメッセージをパーティーBに送信します
  • パーティBがメッセージを処理します
  • パーティBは、処理された画像のアドレスと、そのメッセージをパーティAにルーティングする指示を含むメッセージをメッセンジャーに送信します
  • メッセンジャーはパーティAに、処理された画像アドレスを含むパーティBからのメッセージを送信します
  • パーティAは、処理された画像への参照を持っているため、作業が完了したと見なします。
  • 将来、パーティAが画像を必要とするとき、アドレスを使用して画像を取得します(他のパーティにメッセージを送信することにより)

ここに問題がありますか?どちらの場合も、当事者Aはまで画像アドレスを取得することはできませんした後、乙は、画像を処理します。しかし、パーティAはすぐに画像を必要とせず、すべての権利により、処理がまだ完了していてもそれほど気にすることはできません!

私たちは、Bがその当事者BがAに伝えることによって、かなり簡単にAMQPのケースでこの問題を解決することができ受け入れ Aに画像がどこのアドレスを与える、処理のために画像をなります完了を処理した後に。その後、パーティBは、画像処理が終了したことを示すメッセージを将来Aに送信できます。AMQPメッセージングによる救助!

推測を除いて:RESTで同じことを達成できます。AMQPの例では、「here is the processing image」メッセージを「イメージは処理中です。後で取得できます」というメッセージに変更しました。RESTful HTTPでこれを行うには、202 AcceptedコードをContent-Locationもう一度使用します。

  • パーティAはHTTP POSTメッセージをパーティBに送信しますContent-Type: image/jpeg
  • パーティB 202 Acceptedは、処理が終了したかどうか、および処理が完了したときに画像が利用できる場所を説明する何らかの「非同期操作」コンテンツを含む応答を直ちに送り返します。またContent-Location: <link>202 Accepted応答には、応答本文が何であれ、リソースへのリンクであるヘッダーが含まれます。この場合、それは非同期操作へのリンクであることを意味します!
  • パーティAは、処理された画像への参照を持っているため、作業が完了したと見なします。
  • 将来、パーティーAが処理済みのイメージを必要とするとき、ヘッダーでリンクされている非同期操作リソースを最初にGETしてContent-Location処理が終了したかどうかを判断します。その場合、パーティAは非同期操作自体のリンクを使用して、処理されたイメージを取得します。

ここでの唯一の違いは、AMQPモデルで、パーティBがパーティAに画像処理の完了を通知することです。しかし、RESTモデルでは、パーティAは、実際に画像が必要になる直前に処理が行われたかどうかをチェックします。これらのアプローチは同等にスケーラブルです。システムが大きくなると、非同期AMQP戦略と非同期REST戦略の両方で送信されるメッセージの数は、同等の漸近的な複雑さで増加します。唯一の違いは、クライアントがサーバーの代わりに追加のメッセージを送信することです。

しかし、RESTアプローチには、動的発見とプロトコルネゴシエーションというもう少しのトリックがあります。同期と非同期の両方のREST対話がどのように開始されたかを検討してください。パーティAはパーティBにまったく同じリクエストを送信しましが、唯一の違いはパーティBが応答した特定の種類の成功メッセージです。パーティAが画像処理を同期または非同期のどちらにするかを選択した場合はどうなりますか?パーティAが、パーティBが非同期処理さえ可能であるかどうかを知らない場合はどうなりますか?

さて、実際には、HTTPにはすでにこのための標準化されたプロトコルがあります!これはHTTP設定、特にrespond-asyncRFC 7240セクション4.1の設定と呼ばれます。パーティAが非同期応答を希望する場合Prefer: respond-async、最初のPOST要求にヘッダーが含まれます。パーティBがこのリクエストを尊重することを決定した場合、202 Acceptedを含む応答を送り返しPreference-Applied: respond-asyncます。それ以外の場合、パーティBは単にPreferヘッダーを無視し、201 Created通常どおり送信します。

これにより、パーティーA はサーバーとネゴシエートし、通信している画像処理の実装に動的に適応できます。さらに、明示的なリンクを使用することで、パーティAはB以外のパーティについて知る必要がなくなります。AMQPメッセージブローカーも、画像アドレスを実際に画像データに変換する方法を知っている謎のパーティCも、2番目のB非同期もありません同期要求と非同期要求の両方を作成する必要がある場合などに必要です。必要なもの、必要に応じて必要なものを簡単に記述し、ステータスコード、応答コンテンツ、リンクに反応します。加えるCache-Controlは、データのローカルコピーをいつ保持するかを明示的に指示ヘッダー、サーバーはクライアントがローカル(またはオフライン)のコピーを保持できるリソースとネゴシエートできるようになりました。これが、RESTで疎結合のフォールトトレラントマイクロサービスを構築する方法です。


1

純粋にイベント駆動型である必要があるかどうかは、もちろん特定のシナリオに依存します。本当に必要であると仮定すると、次の方法で問題を解決できます。

さまざまなイベントをリッスンし、ペイロードで情報をキャプチャすることにより、データのローカルの読み取り専用コピーを保存します。これにより、正確なアプリケーションに適した形式で保存されたデータの読み取りが高速(er)になりますが、データが最終的にサービス全体で一貫性を持つことも意味します。

GET /users/1このアプローチでモデルを作成するにはUserCreatedUserUpdatedイベントとイベントをリッスンし、ユーザーデータの有用なサブセットをサービスに保存します。そのユーザー情報を取得する必要がある場合は、ローカルデータストアにクエリを実行するだけです。

少しの間、/users/エンドポイントを公​​開するサービスがいかなる種類のイベントも公開しないと仮定しましょう。この場合、作成するHTTPリクエストに対する応答をキャッシュするだけで、同様のことを実現できます。そのため、ある時間枠内でユーザーごとに複数のHTTPリクエストを作成する必要がなくなります。


わかります。しかし、このシナリオでのクライアントへのエラー処理(およびレポート)はどうでしょうか。
トニーE.スターク

つまり、UserCreatedイベントを処理するときに発生するエラー(たとえば、ユーザー名やメールの重複、データベースの停止など)をRESTクライアントに報告するにはどうすればよいですか。
トニーE.スターク

アクションを実行している場所によって異なります。ユーザーシステム内にいる場合は、すべての検証を行い、そこでデータストアに書き込み、イベントを発行できます。そうでなければ、私はに標準のHTTPリクエストを実行するために完全に受け入れられるようにそれを見/users/たエンドポイント、およびそれが成功した場合、そのシステムは、そのイベントを公開することができ、そして新しいエンティティとのリクエストに応える
アンディ・ハント

0

イベントソースシステムでは、通常、状態を表すもの(データベースやデータの集計ビューなど)が変更されると、非同期の側面が作用します。例を使用すると、GET / api / usersの呼び出しは、システム内のユーザーのリストの最新の表現を持つサービスからの応答を単に返すことができます。別のシナリオでは、GET / api / usersへのリクエストにより、サービスはユーザーの最後のスナップショット以降のイベントストリームを使用して別のスナップショットを作成し、結果を返すだけでした。イベント駆動型システムは、必ずしも要求から応答まで完全に非同期ではありませんが、サービスが他のサービスと対話する必要があるレベルにある傾向があります。多くの場合、非同期的にGETリクエストを返すことは意味をなさないため、単にサービスの応答を返すことができますが、

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.