データ重複のないマイクロサービス


19

最も単純なマイクロサービス設計であっても、データの重複や共有データベースを回避するのが難しいと感じているため、何かが足りないと思っています。これが私が直面している問題の基本的な例です。誰かがWebアプリケーションを使用して在庫を管理していると仮定すると、2つのサービスが必要になります。1つはアイテムと在庫数を管理する在庫管理用、もう1つはユーザーデータを管理するユーザーサービス用です。データベースの在庫者の監査が必要な場合、在庫サービスのデータベースにユーザーIDを最後に在庫された値として追加できます。

アプリケーションを使用して、不足しているすべてのアイテムと、前回アイテムを在庫していた人のリストを確認して、再度在庫を補充するよう依頼することができます。上記のアーキテクチャを使用して、在庫サービスにリクエストを行い、数量が5未満のすべてのアイテムのアイテム詳細を取得します。これにより、ユーザーIDを含むリストが返されます。次に、インベントリサービスから取得したユーザーIDのリストのユーザー名と連絡先の詳細を取得するために、ユーザーサービスに対して別の要求が行われます。

これは非常に非効率的なようで、複数のデータベースクエリを作成するさまざまなサービスAPIに対して複数のリクエストを行うまで、これ以上多くのサービスを必要としません。別の方法は、インベントリデータにユーザーの詳細を複製することです。ユーザーが連絡先の詳細を変更した場合、他のすべてのサービスを通じて変更を複製する必要があります。しかし、これは、マイクロサービスの限定されたコンテキストの考えに適合しないようです。また、単一のデータベースを使用してこれを異なるサービス間で共有し、統合データベースのすべての問題を抱えることもできます

これを実装する正しい/最良の方法は何ですか?


5
マイクロサービスのパラドックスへようこそ。物事をより単純にすると思われるものは、実際には物事をより複雑にします。
ロバートハーヴェイ

「正しい」方法は常に同じです。特定の目的に最適な方法を見つけてください。
ロバートハーベイ

1
@RobertHarveyそれは常にそうですが、私は教科書のマイクロサービスの方法を理解しようとしています。理想的な世界でどのように機能するかを理解したら、ユースケースに合わせて喜んで変更します。
ジェランアンダーソン

1
しかし、機能性のないソフトウェア要件である効率性の観点から質問を組み立てます。効率の問題を解決する方法は、データベースに直接尋ねることです。
ロバートハーヴェイ

1
私はあなたの質問とまったく同じように質問を書き込もうとしていましたが、MSAには合理的なシンプルなWebアプリケーションの利点がまだありません。多くの場合、物事をそれほど複雑にすることなくモジュール性を達成できると思います。
-Glasnhost

回答:


9

複製する必要がある場所を完全に見落としました。

マイクロサービスの中心的な原則は、サービスが単一の機関であることです。つまり、在庫管理とユーザー管理を完全に分離できます。ユーザー管理は、在庫システムの存在すら知らないように設計します。

ただし、ユーザーID以外のユーザーに関する情報を保存しないように、インベントリシステムを設計します。ユーザー情報の変更を伝播する問題を処理します。

ログ、監査、印刷出力など、在庫情報とユーザー情報の両方を必要とするものについては、情報が変更されても更新されません。彼らは何があったかの記録です。繰り返しますが、変更を伝播しません。

そのため、どの場合でも、最新のユーザー情報が必要な場合は、ユーザー情報サービスに問い合わせてください。


@Geraint:システムでどのような複製が発生しているのか、より具体的に説明していただけますか?
ロバートハーヴェイ

1
ありがとう。複製では、ユーザーの連絡先の詳細をインベントリサービスにコピーすることを参照しましたが、これに対処しました(つまり、必須ではありません)。結合を使用してインベントリデータとユーザーデータを取得できる単一のリレーショナルデータベースから、最初の結果が返されるまで2番目のAPI呼び出しを開始できない2つの異なるAPI呼び出しを行うことは、直感に反するようです。しかし、それはマイクロサービスを使用するか他の何かを使用するかについての評価の一部だと思います。
アンダーソン

DBが両方を管理する場合に使用するのと同じトリックです。ユーザー情報をインベントリテーブルにコピーしません。外部キーを与えます。ユーザーIDは、サービス間で同じジョブを実行しています。ただユニークにしてください。
candied_orange

It seems counter-intuitive to move from a single relational database where I could get the inventory data and the user data with a join「理想的には」サービスごとに1つのストア(またはそれ以上)があることに注意してください。ですから、「境界」の間には「結合」のようなものは何もありません。その理由は単純で、DBはサービス間のカップリングを生成します。@CandiedOrangeの提案とは異なり、サービス間で最小限のデータを複製できると思います。変更する可能性が低いデータを参照しています。「プロが」おそらく「短所」オフ設定します。このアップデートパッケージは、効率性とパフォーマンスが向上し(との両方が必要とされている)場合
LAIV

@GeraintAnderson効率が必要な場合(定義により非機能要件である場合)、それを行う方法があります。つまり、Inventory Serviceからデータのページ(10要素など)を要求し、各ページを取得してそのページを使用してUser Serviceからデータを要求し、最後に集約します。こうすることで、独立したサービスの並列性を活用しながら境界を維持できます。それでも、解決する必要のあるアプリケーションの本当のボトルネックとして認識されるまで気にしないでください。1秒間の夜間ジョブでさらに1/2秒間待機することは誰にとっても重要ではありません。
デリオス

10

データの重複を避けるのは難しいと思っています。...

マイクロサービスアーキテクチャに関するMicrosoftの電子書籍によると、データの複製に問題はありません。基本的に、データを複製すると、サービス間の分離が促進されるため、単一の機関としての役割が強化されます。関連する一節:

そして最後に(そして、これはマイクロサービスを構築する際にほとんどの問題が発生する場所です)、最初のマイクロサービスが他のマイクロサービスによって元々所有されているデータを必要とする場合、そのデータの同期リクエストを行うことに依存しません。代わりに、結果整合性を使用して(通常は統合イベントを使用して)、そのデータ(必要な属性のみ)を初期サービスのデータベースに複製または伝播します。


1
私はまったく同意しません。保守が難しくなります。何かを追加、更新、または削除する必要がある場合に、マイクロサービス間でトランザクションを実装できます。単一障害点を防ぎたい場合は、リクエストまたはその他の種類のキャッシュを使用できます。
アラン

@AlanSereb維持するのは難しいですが、ポイントは他の選択肢がないことです。たとえば、2つのデータベースにあるオブジェクト間でFKを作成する必要がある場合はどうなりますか?ローカルDBでクエリを作成するときに一貫性を確保する唯一の方法は、データの複製を取得することです。ご覧
David D.

同意する。別の優れたアプローチは、イベントソーシングルートを取ることです。そして、すべての変異はイベントパイプラインを介して実行されます
アランセレブ

3

在庫サービスに対してリクエストが行われ、数量が5未満のすべてのアイテムのアイテム詳細を取得します。これにより、ユーザーIDを含むリストが返されます。次に、インベントリサービスから取得したユーザーIDのリストのユーザー名と連絡先の詳細を取得するために、ユーザーサービスに対して別の要求が行われます。

たしかにそう。

確かに、モノリスでは、関連するアイテムを照会するインベントリモデルを作成し、それをユーザーモデルにフィードして同じデータを取得できます。

または、同じリレーショナルデータベースにそれらを配置し、データベースがインベントリテーブルとユーザーテーブルを取得するSQLを記述している場合、さらに処理することができます。これにより、いくつかの魔法が実行され、目的のデータが取得されます。

かかわらず、あなたがそれを行う方法の、どこかだろう、本質的に、在庫システムからユーザーIDのリストを取得し、ユーザーのシステムにそれらを供給し、データのリストをコンパイルするコードです。

答える必要がある質問は、パフォーマンスとメンテナンス、およびその他の「ソフト」品質についてです。

マイクロサービスの主な利点はスケーリングです。1台のマシンに1万人のユーザーがいて、少し遅い場合は、別のマシンを追加すると、システムの速度が2倍になります。さらに8つ追加すると、10倍の速度になります。(線形スケーリングはおそらく楽観的ですが、それは理想的なものであり期待するほど不合理ではありません。)

そして、これはサービスごとです。インベントリシステムがボトルネックの場合、ユーザーに関するレポート以外にも使用されますそのサービスだけにマシンを追加できます。機械も特化できます。このサービスは大量のメモリを必要とし、そのサービスは重い計算を行い、より多くのCPUを必要とします。

スケーリングが必要ない場合、マイクロサービスにはもう1つの利点があります。それらはモジュール式です。もちろん、モノリシックアプリはモジュール化することもできます。データベースは正規化されています... マイクロサービスは固体鋼で分離されています。

あなたのユーザーシステムが文字通り発火した場合、それはインベントリシステムに少しも影響を与えません。誰が何を在庫したかについてのきれいなレポートを印刷することはできませんが、顧客は在庫のあるアイテムがあることを知っているので安全に注文を出すことができます。

また、リレーショナルデータベース(*)で行うよりも、microservicesデータを複製することはありません。リレーショナルデータベースでは、結合を行うことができます。これに相当するのは、説明したようなコードのリストをマージすることです。

ビューを追加することもできますが、同等の方法は、マージを行う新しいサービスを追加することです。その結果、3つの要求が発生します。1つは新しいサービスに、それからそのサービスは元の2つを行います。リレーショナルデータベースには、ビューを最適化する派手なものがあり、サービスレベルで実装する必要があります。「無料」では入手できません。

2つの値が一致しない場合、どちらが間違っているかがわかるという点で、キャッシュはデータ複製とは異なります。多くの場合、一貫性を犠牲にして可用性を高めるためにマイクロサービスで使用されます(CAP定理)。リレーショナルデータベースは一貫性の祭壇で可用性を完全に犠牲にしているため、あまり一般的ではありません。マイクロサービスには、キャッシングを簡単にする固有のものは何もないと思いますが、実際にはキャッシングが主な関心事であり、マイクロサービスでキャッシングを簡単にします。

(*)マイクロサービスの群れでデータを複製することが理にかなっている場合、おそらく同等のリレーショナルデータベースで意味があるでしょう。


3
「マイクロサービスでデータを複製しない」という部分まで、私はあなたの答えが本当に好きでした。データの複製が正しいアプローチである場合があると思います。耐障害性と自律性が向上します。ユーザーサービスがダウンした場合でも、在庫サービスは、在庫の少ないリストと、最後に在庫したユーザーを表示できます。
ピーターポンペイ

1
@peterpompeii私は、データの複製ではなく、そのキャッシングと呼びます。データの複製とは、1つのデータムに対して更新する場所が2つある場合です。1つの場所がある場合はキャッシュし、他の場所に自動的に伝播します。また、私はリレーショナル以上のことを言いました。リレーショナルデータベースでデータを複製することが理にかなっている場合、マイクロサービスで理にかなっています。私たちは同意し、その部分はより明確になる可能性があると思いますが、今は携帯電話しか持っていないので、今すぐテキストを更新しません。
オダリック

@PeterPompeiiキャッシングに関する追加セクションが、あなたの懸念のいくつかに対処することを願っています。
オダリック

1
@Odalrickが説明したことは、データ複製のように聞こえます。レプリケーションとキャッシングはどちらもデータを複製する形式です。複製とは、コピーに必要なすべてのデータが常にあることが保証されている場合です。キャッシングはオンデマンドです。キャッシングは失敗する可能性があります。可用性のキャッシュは、パフォーマンスのキャッシュほど意味がありません。TL; DR何かの完全なコピーを十分な一貫性で保存している場合、ミスをチェックする必要がないことが保証されますが、キャッシュではありません。
ブランドン

1
@Brandonレプリケーションとキャッシュのもう1つの違いは、違いがある場合にどのデータが間違っているかを知る方法です。レプリケーションは、データのマージ方法に関するいくつかのルールを定義します。一方、キャッシュは常に行われます。キャッシュが間違っています。
オダリック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.