web-dev-qa-db-ja.com

異なるマイクロサービス間の共有ドメインモデル

2つの異なるマイクロサービスのシナリオを想像してみてください。 1つはサービス内で認証を処理し、もう1つはユーザー管理を処理します。どちらもユーザーの概念を持ち、お互いの通話を通じてユーザーについて話し合います。

「ユーザー」のドメインモデルはどこに属しますか?それらは両方とも、ユーザーがデータベースのレベルで何であるかについて異なる表現を持っているでしょうか? API呼び出しで使用するUserDTOがある場合はどうなりますか?どちらもそれぞれのAPIに1つありますか?

この種のアーキテクチャの問題に対する一般的に受け入れられている解決策は何ですか?

65
Kristof

マイクロサービスアーキテクチャでは、それぞれが他から完全に独立しており、内部実装の詳細を隠す必要があります。

モデルを共有すると、マイクロサービスを結合して、各チームが制限なしにマイクロサービスを開発できる最大の利点の1つを失い、他のマイクロサービスをどのように進化させるかを知る必要がなくなります。それぞれに異なる言語を使用することもできることを覚えておいてください。マイクロサービスを結合し始めると、これは難しいでしょう。

それらがあまりにも関連している場合、@ soruが言うように、それらは本当に1つのものであるかもしれません。

関連する質問:

38
gabrielgiussi

2つのサービスが十分に絡み合っており、DTOや他のモデルオブジェクトを共有せずにそれらを実装するのが面倒な場合は、2つのサービスを使用すべきではないという強い兆候です。

確かに、この例は2つのサービスとしてはほとんど意味がありません。 「ユーザー管理」の仕様が複雑すぎて、チーム全体が非常に忙しくなり、認証を行う時間がないと想像するのは困難です。

何らかの理由でそれらがそうである場合、彼らは基本的に任意の文字列である OAuth 2. のように使用して通信します。

13
soru

これらは、2つの別個の境界コンテキスト(ドメイン駆動設計の用語では)と考えることができます。認証コンテキストの「ユーザー」と他のコンテキストの「ユーザー」を関連付けるために使用されるIDを除いて、それらはデータを共有しないでください。彼らはそれぞれ、「ユーザー」が何であるかを表す独自の表現と、ビジネス責任を実行するために必要な情報である独自のドメインモデルを持つことができます。

ドメインモデルは実際の「もの」をモデル化しようとするのではなく、特定のコンテキスト(アイデンティティ/承認管理、人事など)におけるそのものをモデル化することを忘れないでください。

4
pnschofield

どちらもユーザーの概念を持ち、お互いの通話を通じてユーザーについて話し合います。

@soruの発言にも同意します。あるサービスが別のサービスのデータを必要とする場合、それらの境界は間違っています。

@pnschofieldが思いついた素晴らしい解決策は、サービスを境界付きコンテキストとして扱うことです。

簡単に言えば、主題について話します。共有ドメインモデルはサービスの自律性を殺し、マイクロサービスシステムを分散モノリスに変えます。これは明らかにモノリスよりも悪いです。

したがって、未解決の一般的な問題がまだあります。サービスまたはコンテキストの境界を定義して、それらが高い凝集性と疎結合の良さで成長できるようにする方法です。

私は自分のコンテキストをビジネス機能として扱うソリューションを思いつきました。それは、より高いレベルのビジネス責任、ビジネス機能であり、全体的なビジネス目標に貢献します。ビジネス価値を得るために組織が歩む必要のあるステップとしてそれらを考えることができます。

サービスの境界を特定するときに実行する私の典型的な手順は次のとおりです。

  1. より高いレベルのビジネス機能を識別します。通常、それらは同じドメインの組織間で類似しています。 Porterのバリューチェーンモデル をチェックすると、どのような感じになるかがわかります。
  2. 各機能内で、サブ機能をより深く掘り下げて識別します。
  3. 機能間の通信に注意してください。組織が何をしているか見てください。通常、通信は機能内に集中し、その結果を残りの部分に通知します。したがって、技術アーキテクチャを実装する場合、サービスはイベントを介して通信する必要もあります。これには複数のプラスの影響があります。このアプローチにより、サービスは自律的でまとまりのあるものになります。同期通信や分散トランザクションは必要ありません。

おそらく、この手法の example は、あなたにとって何らかの興味があるでしょう。このアプローチは本当に有益だと思ったので、遠慮なくあなたの考えを知らせてください。確かにそれはあなたのためにもうまくいくことができます。

2
Zapadlo

マイクロサービスは「何も共有しない」ことではなく、「できるだけ共有しない」ことです。ほとんどの場合、「ユーザー」は本当に一般的なエンティティです(ユーザーがいくつかの共有識別子(userId/email/phone)で識別されるためです)。定義によって共有されるそのような種類のエンティティ。 Userモデルは1つのマイクロサービスの範囲外です。したがって、ユーザー(最も一般的なフィールドのみ)を配置する必要のあるグローバルスキーマが必要です。厳密にはidのみです。

1

これは非常に優れたマイクロサービスガイドのようです: https://docs.Microsoft.com/en-us/dotnet/architecture/microservices/ 、これはマイクロサービスがドメイン駆動型であることを示唆しています設計(DDD)および境界コンテキストパターン( https://docs.Microsoft.com/en-us/dotnet/architecture/microservices/architect-microservice-container-applications/data-sovereignty-per-microservice =)、つまり、データを共有しないでください。あなたが何をしていて、あなたが契約(DTOまたはイベント)を管理しているかについての推奨事項は見つかりませんでした。

1つのオプションは、すべてのサービスがコントラクトクラスの独自のコピーを持つようにすることです。実際にはそれは良い考えではありません。ほとんどの場合、マイクロサービス間の通信は、RESTまたはメッセージキューとのJSONメッセージの交換に物理的に要約されます。JSONは大文字と小文字を区別する形式です。つまり、 "userID"は "userId"と実質的に異なります。そして、「UserId」、これは意味的には同じであることに関係なく、そのためだけに多くの問題が発生しており、1つの大きなランドスケープの同期は非常に困難です。

私が本当に気に入っているのは、データコントラクトを保持する個別のライブラリ(NuGet、Mavenなど)があり、簡単に再利用できることです。大きな景観の場合、ドメインに基づいて分割される場合があります。進化する可能性があり、バージョンも異なります。互換性に影響しない変更の場合、マイクロサービスは古いバージョンを引き続き使用できます。新しいAPIバージョンの場合、新しいバージョンがリリースされ、必要な人は誰でも移行できます。

契約を定義するためのセマンティック言語を使用できるアプローチについて聞いたことがあります。これは、さまざまなプログラミング言語の特定のクラスにコンパイルされます。データ/契約の定義が最初に来るという考え方です。

0
llatinov