モジュールという用語は、 モジュール対から取られています。 マイクロサービス 。 また、「マイクロリス」または「モノサービス」という用語は、マイクロサービスとモノリスの間の何かを表すために時々使用されます。 しかし、「モジュール」という用語には既によく知られた意味が既にロードされているという事実にもかかわらず、私の意見では、他のオプションよりも適しています。 更新:コメントで、 レガは「組み込みマイクロサービス」という用語を使用しました。「モジュール」よりもアプローチの本質を説明しています。
モノリスとマイクロサービスは非常に異なるアプローチであるため、両方からベストを引き出すためには、バランスを取ることが重要です。 そうでなければ、 OSGiのようなモンスターを取得します。
私は2009年からマイクロサービスを書いていますが、実際のプロジェクトではマイクロサービスの代わりにモジュールを使用しようとしませんでした-以下に説明するすべては、上記のバランスがどうあるべきかについての私の仮定であり、理論的な批判と実用的な検証の両方が必要です。
モジュールとは何ですか?
モジュールはマイクロサービスのようなもので、単一のアプリケーション内にのみ実装され、そのようなモジュールのグループと非常に小さなパーツで構成され、これらすべてのモジュールの初期化と起動に関与します。
正式にはこのようなアプリケーションはモノリスと呼ぶことができますが、このアプローチはマイクロサービスとより多くの共通点があるため、マイクロサービスアプローチと比較することは理にかなっています。 マイクロサービスのように、各モジュールは:
- 慎重に設計および文書化されたAPIが必要であり、同じアプリケーションで実行されている他のコードからアクセスできる必要があります(この制限の制御には言語レベルおよび/または開発ツールでのサポートが必要です)。
- 他のモジュールのコードとは独立して実行され、ネットワークプロトコルを使用せずに他のモジュールのAPIと効果的に対話できる必要があります(これには、言語レベルでのサポートが必要です:スレッド/ゴルチン/アクター、チャネル/メッセージなど)。
- 独自のデータウェアハウスを使用する必要があります(必要な場合)。
- 別のレポジトリまたはモノレポジトリアプリケーションにすることができます。
- さまざまなアプリケーションで使用できます。
- ネットワーク経由でAPIへのアクセスを提供できます(モジュールのみがこれを行う必要はありません。アプリケーション内ではアクセスは完全ではありませんが、部分的です)。
マイクロサービスとは異なり、モジュールは:
- 通常、独立してデプロイすることはできません(実行中のアプリケーションでコードの一部のホットスワップがサポートされていない限り)。
- アプリケーション全体に関係なく再起動できません。
- 他のモジュールから独立してスケーリングすることはできません。
- モジュール間の分離を破ることを決定した場合、他のモジュールからの「自分の」ファイルへのアクセスを妨げることはできません。 言語もツールもそのような違反を防ぐことはできないため、ここでは、開発者自身の規律とコードレビューのみに依存する必要があります。
- おそらく、他のモジュールと共有されているライブラリを制限なく使用できますが、ここではわかりません。 これによるマイナスの影響は、従来のマイクロサービスほど重要ではありませんが、それでも変わりません。 特に、将来的にモジュールが本格的なマイクロサービスとして起動される場合(そして、これは概してこれまでのところ干渉しません-モジュールは必要に応じて個別のマイクロサービスに非常に簡単に変換されます)。
通常のライブラリとは異なり、モジュールは:
- それを使用するAPIコードと共通データを共有しないでください-すべてのデータは、コピーとして、または大量のデータがあり、読み取り専用アクセスが必要な場合は、不変データ構造の形式でAPIを介して送信する必要があります(サポートが必要です)言語レベル)。
- 他のモジュールが呼び出すことができる機能を提供しません-すなわち。 外部の実行スレッド(スレッド、ゴルーチンなど)でコードを実行しないため、モジュールコードで発生する可能性のある例外も呼び出し元のコードから分離します。
- モジュールには、アプリケーションの起動時に呼び出されるモジュールの初期化と起動のためのパブリック関数がありますが、他のモジュールからの(再)呼び出しは意図されていません。
- 他のモジュールから完全に分離された独自の:
- 構成(アプリケーションの起動時に彼に渡されます)。
•すべてのモジュールに共通のロギング設定が含まれる場合があります。 - データウェアハウス(必要な場合)。
•更新中のこのデータおよび移行のスキーマのバージョン管理のサポートもモジュールの責任です。ただし、各モジュールのデータ移行の開始は、すべてのモジュールに共通のアプリケーション展開プロセスの一部である場合があります。
- 構成(アプリケーションの起動時に彼に渡されます)。
ほとんどの場合、モジュールはサービスのレジストリを必要としません-自身を登録して他のモジュールを検索する代わりに、起動時にアプリケーションが各モジュールの初期化関数を呼び出すときに、起動時に必要な他のモジュールのインターフェースを取得します(モジュール間の依存関係によって決定される順序で) 副作用として、これにより、モジュール間の周期的な依存関係が検出された場合はすぐに検出されます(可能であれば、それらを取り除くためにアーキテクチャを変更します)。
モジュールはどこに必要ですか
一定の複雑さ( 偶発的な複雑さ )があり、各マイクロサービスでも同じです(サービスの登録/発見、それらへの接続と再接続、サービス間の認証、(de)トラフィックマーシャリングと暗号化、ループバックリクエストブレーカーの使用、リクエストトレースの実装など)。 同様の一定の操作上の複雑さが追加されています(テストとロールアウトの自動化、詳細な監視の実装、ログの集計、サービスの登録と検索、サービスの構成の保存、監査などのためのサービスサービスの使用など)。 マイクロサービスの数が増えても、この複雑さは増えず、これらのコストを補う以上のマイクロサービスの利点があります。
ただし、特定のアプリケーションのビジネスロジックに依存する複雑さはあり、アプリケーションの開発に伴い増加します。少なくとも、拡張性と高可用性を必要としないアプリケーション(または少なくとも、そのようなアプリケーションのコードの一部を除くアプリケーションでは、外部サービスと対話する必要があることは明らかです):
- べき等と非べき等の要求を分離する必要性。
- クライアント上のすべてのリクエスト:
- タイムアウト(要求ごとに異なる場合があります)を使用する必要があります。
- 物事をスピードアップするために、より多くの非同期性を使用する必要性。
- 最終的な一貫性のより多くの状況と結果として生じる困難。
•含む 他のサービスからのデータをキャッシュする必要がある場合があります。 - いくつかのクエリを繰り返す必要性:
•繰り返しの回数または時間の制限を使用する。
•繰り返し間の遅延の使用。
- さらに、非べき等クライアント要求の場合:
- クエリを繰り返すときに重複を識別する機能を実現する必要性。
- さらに、べき等でないサーバー要求の場合:
- 重複したリクエストを識別して処理する必要性(各リクエストのビジネスロジックに応じて異なる)。
- 場合によっては、次と同じ順序でクエリを実行する必要があります。
彼らは送られました。
正しいモジュール方式により、マイクロサービスの多くの利点を維持できます(言語レベルおよび/または開発ツールで必要なサポートがある場合)が、このアプリケーションの不必要なスケーラビリティと高可用性機能を失うことに加えて、他にもあります:
- モジュールがクラッシュすると、アプリケーション全体がクラッシュします。
- ビルドとテストの速度が低下します。
- ビルド速度が本当の問題かどうかはわかりません-スピードアップする方法はたくさんあります。
- 原則として、/ PRブランチをテストする場合、変更されたモジュールのテストのみを実行し、展開前にのみプロジェクト全体のテストを実行できます。これにより、この問題が十分に平準化されます。
- 起動速度が低下します(キャッシュのウォームアップなど)。
- ここでの問題は、実際のスローダウンではそれほど問題ではありませんが、多くのサービスが起動するときに、独立して(再)開始する複数のサービスに「広がる」という事実です。 ただし、起動が遅いことによる目に見える効果は、この事実をキャンセルしません。
モジュラーアプローチには、次の新しい利点もあります。
- サービスモジュール間の相互作用の速度が向上し、非同期、最終的な一貫性、およびキャッシュの必要性が大幅に減少します。
- モジュールには外部(ネットワーク)APIがありませんが、このモジュール(同じアプリケーションの他のモジュール)を使用するクライアントの展開により、これらの変更を原子的に簡単に変更および展開できます。
- モジュール間のコラボレーションは、マイクロサービスのグループよりもテストが簡単です。
- monorepo(必要な場合)を使用する方が簡単ですが、これは必須ではありません。
- Monorepoは、リファクタリングとAPIの変更を簡素化します。少なくとも現時点では、モジュールにネットワークインターフェースと外部クライアントがないことが保証されています。
まとめ
一般に、アプローチは非常に魅力的です-マイクロサービススタイルで開発された本当によく分離された部分の形でモノリシックアプリケーションを書く機会を得ます(さらに、これは主に内部規律ではなく言語および/またはツールによって制御されます)さまざまなレポのさまざまなチームを含む)、「手首を軽く動かす」ことで、本当に必要な場合に実際のマイクロサービスに変えることができます...一方、MOD間でメッセージングを使用できます 非同期、結果整合性とネットワークエラーの処理の複雑さを排除し、シンプルでRPCの非常に迅速な交換などのアプリケーション内の、。
現在、このアプローチに必要なサポートはすべての言語で利用できるわけではありませんが、いくつかの言語では:「モジュールとマイクロサービス」の記事の著者がJava 9のモジュール性サポートについて書いています。Goでは、Erlangによると、 Dawn of the Microlith-Elixirによるモノサービス スクリプト言語でモジュールを実際に分離できるかどうかはわかりませんが、NodeJSのマイクロモノ、 コメント legaでlegaをPythonアプローチにリンクする試みがあります...
トピックについての考えがある場合(またはさらに良い-同様の原則に関する実際のプロジェクトの経験)、またはトピックに関する記事/プロジェクトへの追加リンクがある場合-コメントを書いて、それらを記事で補足しようとします。