マイクロサービス間でデータを同期する適切な方法は何ですか?


17

私はマイクロサービスアーキテクチャが比較的新しいです。適度なサイズのWebアプリケーションがあり、現在進めているモノリシックシステムではなく、マイクロサービスに分割することの長所と短所を比較検討しています。

私が理解している限りでは、マイクロサービスAと、Bそれぞれが他方のデータのサブセットに依存しているものを検討してください。A何かが変更されたというメッセージが投稿された場​​合、Bそのメッセージを消費し、Aの情報のローカルコピーを複製し、それを使用してB必要な処理を実行できます。

ただし、もしBダウンしたり失敗したりしてしばらくすると、再び元に戻ります。そのダウンタイム中に、Aさらに2つのメッセージを公開しました。の情報のBローカルコピーを更新する方法はどのようにしてわかりますAか?

場合確かに、B唯一の消費者であるAのキューは、それはそれがオンラインに戻ったら、それを読み始めることができますが、どのような場合には、そのキューとそれらのメッセージの他の消費者が消費されているがありますか?

より具体的な例として、マイクロサービスがダウンしているUsers間にBillingサービスの電子メールアドレスが更新された場合、Billingマイクロサービスが再び復旧した場合、電子メールが更新されたことをどのようにして知ることができますか?

マイクロサービスが復旧すると、「ちょっと復旧しました。現在の情報をすべて教えてください」というブロードキャストを行います。

一般に、データ同期の業界のベストプラクティスは何でしょうか?


1
可能な限り回避するため。
テラスティン

1
なぜOrders何かを知る必要があるのUsersですか?
-kdgregory

これは単なる例です。2つを意味のあるものに置き換えます。
-noblerare

ファンアウトルーティングは、「メッセージが他の誰かによって消費されている」という問題を解決します。しかし、あなたが何を達成しようとしているかは本当に不明瞭です。
ユアン

@Ewan元の投稿を更新して、私が尋ねようとしていることをよりよく説明しました。
-noblerare

回答:


6

もう少し研究を行った後、私はこの記事に出くわしました。この記事から、私がやりたいこと(そして将来の読者)に役立つと思う引用を引き出しました。これにより、命令型プログラミングモデルよりもリアクティブプログラミングモデルを採用することができます。

イベントソーシング

ここでの考え方は、すべてのアプリケーションの状態遷移を不変のイベントの形式で表すことです。その後、イベントは発生時にログまたはジャーナル形式で保存されます(「イベントストア」とも呼ばれます)。また、アプリケーション全体の状態が時間の経過とともにどのように進化したかを表すことを目的として、クエリを無期限にクエリおよび保存することもできます。

これが実現することができますすることmicroserviceがダウンした場合、それが公開されていると、まだ他のイベントが適切なことであるイベントがそのmicroservice、そのmicroserviceが復帰するとき、それはこれを参照することができますの他の例では、たとえば、によって消費されているevent storeすべて取得するにはダウンした期間中に見逃したイベント。

イベントブローカーとしてのApache Kafka

Apache Kafkaの使用を検討してください。ApacheKafkaは毎秒数千のイベントを保存およびディスパッチでき、組み込みのレプリケーションおよびフォールトトレランスメカニズムを備えています。イベントの永続的なストアがあり、ディスクに無期限に保存でき、いつでもトピック(Kafkaの空想キュー)から配信(削除されない)に消費できます。

イベントには、トピック内で一義的に識別するオフセットが割り当てられます-Kafkaはオフセット自体を管理し、「最大1回」または「少なくとも1回」の配信セマンティクスを簡単に提供できますが、イベントコンシューマーがトピックに参加するときにネゴシエートすることもできます、マイクロサービスが任意の時間の任意の場所からイベントの消費を開始できるようにします。通常は、消費者が中断したところからです。ユースケースが「正常に完了」したときに、最後に消費されたイベントオフセットがサービスのローカルストレージにトランザクション的に保持される場合、そのオフセットを使用して「exactly once」イベント配信セマンティクスを簡単に実現できます。

実際、消費者がKafkaに対して自分自身を識別すると、Kafkaはどのメッセージがどの消費者に配信されたかを記録し、それが再び配信されないようにします。

サガ

異なるサービス間の通信が実際に必要なより複雑なユースケースの場合、ユースケースを終了する責任は十分に認識されなければなりません。また、無効なローカル状態をロールバックするには、修正措置をトリガーする必要があります。

これは、サガが登場するときです。サガは、ローカルトランザクションのシーケンスです。各ローカルトランザクションはデータベースを更新し、メッセージまたはイベントを発行して、佐賀の次のローカルトランザクションをトリガーします。ローカルトランザクションがビジネスルールに違反しているために失敗した場合、サガは一連の補正トランザクションを実行し、前のローカルトランザクションによって行われた変更を取り消します。詳細についてはこちらをお読みください。


なぜそんなに複雑な構造を構築したいのか、私にはまだわかりません。通常、各サービスが独自のデータを保持し、要求に応じて他のサービスに提供する方がはるかに簡単です。
J.ファビアン・マイヤー

^ただし、システムの可用性は低下します。高い復元力が必要な場合、複雑な構造が必要になる場合があります。
avmohan

4

「他のすべてのマイクロサービスにデータをプッシュする」というあなたの考え全体に挑戦します。

通常、請求サービスにメールアドレスが必要な場合、特定の顧客のメールアドレスをアドレスサービスに要求するだけです。すべての住所データのコピーを保持する必要はなく、変更があった場合に通知されません。最新のデータから回答を求めて取得するだけです。


この答えはまさに正しいと思います。同期に関連する多くの問題を排除します。実際、さまざまなサービスが情報のコピーを保持しており、同期の問題があるため、このような問題のあるコードを今見ています。
DaveG

2
ご回答有難うございます。では、なぜpub / subモデルとメッセージキューが必要なのでしょうか?「プッシュ」データではなく「プル」しようとしている場合、サービスの遅延が心配です。
-noblerare

私の知る限り、サービスは(pub / subのように)何かが変わってもすぐに反応する必要はありませんが、データが必要な場合があります。それから私はそれを引っ張ります。レイテンシーが心配な場合は、データをキャッシュできますが、データが最新かどうかわからないという犠牲が伴います。ファイルが大きい場合は、何かを再度プルする前に、何か変更があるかどうかを尋ねることもできます。
J.ファビアン・マイヤー

このソリューションには、依存サービスを密結合するというコストがかかることに注意してください。つまり、ユーザーサービスが利用できない場合、電子メールアドレスは利用できなくなります。サービスを個別に展開、スケーラブルにするなどの最初のアイデアの1つ。すべてのサービスがキャッシュや高可用性の保証なしで互いに直接通信する場合、1つのシステムがダウンすると、降りる。
dukethrash

@dukethrashその後、それらの可用性を高めます。
J.ファビアンマイヤー

0

通常のイベントキューをパブリッシャー/サブスクライバーモデルに置き換えることができます。このモデルでは、AサービスはトピックTBマイクロサービスの種類の新しいメッセージをパブリッシュし、同じトピックをサブスクライブします。

理想的にBはステートレスサービスであり、デタッチされた永続性サービスを利用し、同じ共有永続性サービスから読み取りを行って作業を継続するB1つ以上のBサービスインスタンスを生成することにより、障害が発生したサービスインスタンスを置き換えます。

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