Java マイクロサービスの翻訳と適応: 実践ガイド。ガイドの前の部分:
Java のマイクロサービスに固有の問題を、抽象的なものから始めて具体的なライブラリまで見てみましょう。
Java マイクロサービスの回復力を高めるにはどうすればよいでしょうか?
マイクロサービスを作成するときは、基本的に JVM メソッド呼び出しを同期 HTTP 呼び出しまたは非同期メッセージングと交換していることを思い出してください。メソッド呼び出しは (予期しない JVM シャットダウンを除いて) 完了することがほとんど保証されていますが、ネットワーク呼び出しはデフォルトでは信頼できません。機能する場合もありますが、ネットワークが過負荷になっている、新しいファイアウォール ルールが実装されているなど、さまざまな理由により機能しない場合があります。これがどのような違いをもたらすかを確認するために、BillingService の例を見てみましょう。HTTP/REST 復元パターン
顧客が会社の Web サイトで電子書籍を購入できるとします。これを行うには、オンライン ストアを呼び出して実際の PDF 請求書を生成できる請求マイクロサービスを実装しました。現時点では、この呼び出しを HTTP 経由で同期的に行います (ただし、ユーザーの観点からは PDF の生成は即座に行われる必要はないため、このサービスを非同期的に呼び出す方が合理的です。次の例でも同じ例を使用します)セクションを参照して違いを確認してください)。@Service
class BillingService {
@Autowired
private HttpClient client;
public void bill(User user, Plan plan) {
Invoice invoice = createInvoice(user, plan);
httpClient.send(invoiceRequest(user.getEmail(), invoice), responseHandler());
// ...
}
}
要約すると、この HTTP 呼び出しで考えられる結果が 3 つあります。
- OK: 通話は成功し、アカウントは正常に作成されました。
- 遅延: 電話はつながりましたが、完了するまでに時間がかかりすぎました。
- エラー。呼び出しが失敗しました。互換性のないリクエストを送信したか、システムが動作していない可能性があります。
メッセージングの回復力パターン
非同期通信について詳しく見てみましょう。メッセージングに Spring と RabbitMQ を使用していると仮定すると、BillingService プログラムは次のようになります。アカウントを作成するには、RabbitMQ メッセージ ブローカーにメッセージを送信します。そこには、新しいメッセージを待っているワーカーがいくつかあります。これらの作業者は PDF 請求書を作成し、適切なユーザーに送信します。@Service
class BillingService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void bill(User user, Plan plan) {
Invoice invoice = createInvoice(user, plan);
// преобразует счет, например, в json и использует его How тело messages
rabbitTemplate.convertAndSend(exchange, routingkey, invoice);
// ...
}
}
同期 HTTP 接続の場合のように即時に OK または ERROR 応答を受信することがなくなり、潜在的なエラーの見た目が少し異なります。その代わりに、問題が発生する可能性のある 3 つの潜在的なシナリオがあり、次のような疑問が生じる可能性があります。
- 私のメッセージは従業員に届けられ、使用されましたか? それとも紛失したのでしょうか?(ユーザーは請求書を受け取りません)。
- 私のメッセージは一度だけ配信されましたか? それとも複数回配信され、一度だけ処理されますか? (ユーザーは複数の請求書を受け取ります)。
- 構成: 「交換に正しいルーティング キー/名前を使用しましたか?」から「メッセージ ブローカーは正しく構成および維持されていますか? それともキューがいっぱいですか?」まで。(ユーザーは請求書を受け取りません)。
- ActiveMQ のような JMS 実装を使用している場合は、速度を犠牲にして 2 フェーズ (XA) コミットの保証を得ることができます。
- RabbitMQ を使用している場合は、まずこのチュートリアルを読んでから、確認、フォールト トレランス、メッセージの信頼性全般について慎重に検討してください。
- おそらく、Active サーバーまたは RabbitMQ サーバーの構成、特にクラスタリングや Docker との組み合わせに精通している人がいるかもしれません (誰か? ;))
Java マイクロサービスにとって最適なソリューションはどのフレームワークでしょうか?
一方で、Spring Bootなどの非常に人気のあるオプションをインストールできます。.jar ファイルの作成が非常に簡単で、Tomcat や Jetty などの組み込み Web サーバーが付属しており、どこでもすばやく実行できます。マイクロサービス アプリケーションの構築に最適です。最近、部分的にリアクティブ プログラミングからインスピレーションを得た、いくつかの特殊なマイクロサービス フレームワーク、KubernetesまたはGraalVMが登場しました。さらに興味深い候補がいくつかあります: Quarkus、Micronaut、Vert.x、Helidon。最終的には自分で選択する必要がありますが、完全に標準ではない可能性のある推奨事項をいくつか紹介します。 Spring Boot を除いて、すべてのマイクロサービス フレームワークは通常、ほぼ瞬時に起動するため、信じられないほど高速であるとして宣伝されています。 、メモリ使用量が少なく、無限のスケーラビリティ。通常、マーケティング資料には、プラットフォームを巨大な Spring Boot と並べたり、並べて見せたりする印象的なグラフィックが掲載されています。これにより、理論的には、読み込みに数分かかることがあるレガシー プロジェクトをサポートする開発者の神経が解放されます。または、クラウドで作業し、現在必要な数のマイクロコンテナを 50 ミリ秒以内に起動/停止したい開発者。 ただし、問題は、これらの (人為的な) ベアメタルの起動時間と再デプロイ時間は、プロジェクト全体の成功にはほとんど寄与しないことです。少なくとも、強力なフレームワーク インフラストラクチャ、強力なドキュメント、コミュニティ、および強力な開発者のスキルよりも影響力ははるかに小さいです。したがって、次のように考える方がよいでしょう: これまでのところ:- ORM を蔓延させて、単純なワークフローに対して何百ものクエリを生成します。
- 適度に複雑なモノリスを実行するには、無限のギガバイトが必要です。
- 非常に多くのコードがあり、複雑さが非常に高いため (ここでは Hibernate のような潜在的なスロースターターについては話していません)、アプリケーションのロードに数分かかります。
同期 Java REST 呼び出しに最適なライブラリはどれですか?
低レベルの技術面では、おそらく、 Java のネイティブ HttpClient (Java 11 以降)、Apache の HttpClient、またはOkHttpの HTTP クライアント ライブラリのいずれかを使用することになります。ここで「おそらく」と言ったのは、古き良きJAX-RS クライアントから最新のWebSocketクライアントに至るまで、他にも選択肢があるためです。いずれにせよ、HTTP クライアントを生成する傾向があり、自分で HTTP 呼び出しをいじることから離れています。これを行うには、さらに読むための出発点として、 OpenFeignプロジェクトとそのドキュメントを参照する必要があります。非同期 Java メッセージングに最適なブローカーは何ですか?
おそらく、人気のあるActiveMQ (Classic または Artemis)、RabbitMQ、またはKafkaに遭遇するでしょう。- ActiveMQ と RabbitMQ は、従来の本格的なメッセージ ブローカーです。これらには、「賢いブローカー」と「愚かなユーザー」のやり取りが含まれます。
- 歴史的に、ActiveMQ には (テスト用の) インライン化が簡単という利点がありましたが、これは RabbitMQ/Docker/TestContainer 設定で軽減できます。
- Kafka は従来の「スマート」ブローカーとは言えません。代わりに、これは比較的「愚かな」メッセージ ストア (ログ ファイル) であり、賢明なコンシューマが処理する必要があります。
マイクロサービスのテストにはどのようなライブラリを使用できますか?
それはあなたのスタックに依存します。Spring エコシステムをデプロイしている場合は、フレームワークの特定のツールを使用することが賢明です。JavaEE がArquillianのようなものである場合。Docker と非常に優れたTestcontainersライブラリを検討してみる価値があるかもしれません。これは、特にローカル開発または統合テスト用に Oracle データベースを簡単かつ迅速にセットアップするのに役立ちます。HTTP サーバー全体の模擬テストについては、Wiremockを確認してください。非同期メッセージングをテストするには、ActiveMQ または RabbitMQ を実装してから、Awaitility DSLを使用してテストを作成してみてください。さらに、すべての通常のツール ( Junit、AssertJ用のTestNG、およびMockito )が使用されます。これは完全なリストではないことに注意してください。ここでお気に入りのツールが見つからない場合は、コメント欄に投稿してください。すべての Java マイクロサービスのログ記録を有効にするにはどうすればよいですか?
マイクロサービスの場合のロギングは、興味深いですがかなり複雑なトピックです。less または grep コマンドで操作できる 1 つのログ ファイルの代わりに、n 個のログ ファイルが存在することになり、それらが散在しすぎないようにする必要があります。ロギング エコシステムの機能については、この記事(英語) で詳しく説明されています。必ず読んで、「マイクロサービスの観点から見た集中ログ」セクションに注意してください。実際には、さまざまなアプローチが考えられます。システム管理者は、さまざまなサーバーからログ ファイルを収集して 1 つのログ ファイルに結合し、ダウンロード用に FTP サーバーに置く特定のスクリプトを作成します。cat/grep/unig/sort の組み合わせを並列 SSH セッションで実行します。これはまさに Amazon AWS が行っていることなので、マネージャーに知らせることができます。GraylogやELK Stack (Elasticsearch、Logstash、Kibana)などのツールを使用するマイクロサービスはどのようにして互いを見つけるのでしょうか?
これまで、マイクロサービスは相互に認識しており、対応する IPS を認識していると想定してきました。静的構成について話しましょう。したがって、バンキング モノリス [ip = 192.168.200.1] は、プロパティ ファイルにハードコードされているリスク サーバー [ip = 192.168.200.2] と通信する必要があることを認識しています。ただし、物事をより動的にすることもできます。- application.properties ファイルをマイクロサービスにデプロイする代わりに、すべてのマイクロサービスが構成を取得するクラウドベースの構成サーバーを使用します。
- サービス インスタンスはその場所を動的に変更できるため、サービスが存在する場所、IP が何であるか、およびそれらをルーティングする方法を認識しているサービスに注目する価値があります。
- すべてが動的になると、リーダーの自動選出などの新しい問題が発生します。たとえば、タスクを 2 回処理しないように特定のタスクに取り組むマスターは誰ですか? リーダーが失敗したとき、誰が代わりをするのでしょうか?交換はどのような基準に基づいて行われますか?
Java マイクロサービスを使用して認可と認証を整理するにはどうすればよいですか?
このトピックも別の話にする価値があります。繰り返しになりますが、オプションは、カスタム セキュリティ フレームワークを使用したハードコーディングされた基本 HTTPS 認証から、独自の認証サーバーを使用した Oauth2 インストールの実行まで多岐にわたります。すべての環境が同じに見えるようにするにはどうすればよいですか?
マイクロサービスを使用しないデプロイメントに当てはまることは、マイクロサービスを使用するデプロイメントにも当てはまります。Docker/Testcontainers と Scripting/Ansible の組み合わせを試してください。質問は不要です: YAML について簡単に説明します
ライブラリや関連する問題から少し離れて、Yaml について簡単に見てみましょう。このファイル形式は、「構成をコードとして記述する」ための形式として事実上使用されています。Ansible などの単純なツールや Kubernetes などの巨大なツールでも使用されます。YAML インデントの苦痛を体験するには、単純な Ansible ファイルを作成して、期待どおりに機能するまでにファイルをどの程度編集する必要があるかを確認してください。この形式はすべての主要な IDE でサポートされているにもかかわらず、これは可能です。その後、戻ってこのガイドを読み終えてください。Yaml:
- is:
- so
- great
分散トランザクションについてはどうですか? 性能試験?他の話題は?
おそらくいつか、マニュアルの将来の版に登場するでしょう。今のところはこれですべてです。私たちと居て!マイクロサービスの概念的な問題
Java のマイクロサービス固有の問題に加えて、どのマイクロサービス プロジェクトにも現れる他の問題もあります。それらは主に組織、チーム、管理に関連しています。フロントエンドとバックエンドの不一致
フロントエンドとバックエンドの不一致は、多くのマイクロサービス プロジェクトで非常に一般的な問題です。それはどういう意味ですか?ただ、古き良きモノリスでは、Web インターフェイス開発者はデータを取得するための特定のソースを 1 つ持っていました。マイクロサービス プロジェクトでは、フロントエンド開発者はデータを取得するためのソースを突然持つことになります。Java で何らかの IoT (モノのインターネット) マイクロサービス プロジェクトを作成していると想像してください。あなたがヨーロッパ全土で測地機械と工業炉を管理しているとします。これらのオーブンは、温度などの最新情報を定期的に送信します。遅かれ早かれ、おそらく「炉検索」マイクロサービスを使用して、管理 UI でオーブンを検索することになるかもしれません。対応するバックエンドがドメイン駆動設計またはマイクロサービス法則をどの程度厳密に適用するかに応じて、「オーブンの検索」マイクロサービスはオーブン ID のみを返し、タイプ、モデル、場所などの他のデータは返さない場合があります。これを行うには、フロントエンド開発者は、最初のマイクロサービスから受け取った ID を使用して、「炉データの取得」マイクロサービスで 1 回または n 回の追加呼び出し (ページングの実装に応じて) を行う必要があります。 そして、これは実際の (!) プロジェクトから取られたものではあるものの、単なる単純な例にすぎませんが、次の問題を示しています。スーパーマーケットが非常に人気になっているということです。なぜなら、彼らがあれば、野菜、レモネード、冷凍ピザ、トイレットペーパーを買うために10か所の異なる場所に行く必要がないからです。代わりに、1 か所に行くほうが簡単かつ迅速です。フロントエンド開発者やマイクロサービス開発者にも同じことが当てはまります。経営陣の期待
開発者は互いに完全に独立して、それぞれが独自のマイクロサービスで作業できるようになったため、経営者は、(包括的な) プロジェクトのために無限の数の開発者を雇用する必要があると誤解しています。最後 (起動直前) に必要な統合作業はほんの少しだけです。 実際、このアプローチには非常に問題があります。次の段落では、その理由を説明していきます。「より小さな作品」は「より良い作品」と同じではありません
20 の部分に分割されたコードが、1 つの部分全体よりも必然的に高品質になると考えるのは大きな間違いです。品質を純粋に技術的な観点から捉えたとしても、個々のサービスはデータベースからユーザーを選択するために 400 の Hibernate クエリを実行し、サポートされていないコードの層を横断している可能性があります。もう一度、サイモン ブラウンの言葉に戻ります。モノリスを適切に構築できなければ、適切なマイクロサービスを構築するのは困難になります。マイクロサービス プロジェクトでフォールト トレランスについて話すのは非常に遅いことがよくあります。そのため、実際のプロジェクトでマイクロサービスがどのように動作するのかを見るのが怖くなることがあります。その理由は、Java 開発者がフォールト トレランス、ネットワーキング、およびその他の関連トピックを適切なレベルで常に学習する準備ができているわけではないためです。「駒」自体は小さくなりますが、「技術的な部分」は大きくなります。マイクロサービス チームが、データベース システムにログインするための次のような技術的なマイクロサービスを作成するように求められたと想像してください。@Controller
class LoginController {
// ...
@PostMapping("/login")
public boolean login(String username, String password) {
User user = userDao.findByUserName(username);
if (user == null) {
// обработка варианта с несуществующим пользователем
return false;
}
if (!user.getPassword().equals(hashed(password))) {
// обработка неверного пароля
return false;
}
// 'Ю-ху, залогинorсь!';
// установите cookies, делайте, что угодно
return true;
}
}
ここで、チームは、これはあまりにも単純すぎて退屈であるため、ログイン サービスを作成する代わりに、実際の具体的なビジネスへの影響をまったく受けずに、非常に便利な UserStateChanged マイクロサービスを作成したほうがよいと判断する (おそらくビジネス関係者を説得することさえある) かもしれません。また、現在 Java を恐竜のように扱う人もいるので、流行の Erlang で UserStateChanged マイクロサービスを作成しましょう。そして、どこかで赤黒の木を使ってみましょう。Steve Yegge は、Google に応募するには木について隅から隅まで知らなければならないと書いているからです。統合、メンテナンス、および全体的な設計の観点から見ると、これは単一のモノリス内にスパゲッティ コードの層を記述するのと同じくらい悪いことです。人為的でありふれた例でしょうか?これは本当です。ただし、これは現実に起こる可能性があります。
ピースが少ない - 理解度が低い
その場合、システム全体、そのプロセス、ワークフローを理解することについての疑問が当然生じますが、同時に開発者としての責任は、分離されたマイクロサービス [95:login-101:updateUserProfile] に取り組むことだけです。これは前の段落と一致しますが、組織、信頼、コミュニケーションのレベルによっては、マイクロサービス チェーンで偶発的な障害が発生した場合に多くの混乱、肩をすくめ、非難される可能性があります。そして、起こったことに対して全責任を負う人は誰もいません。そして、それは決して不正の問題ではありません。実際、さまざまな部分を接続し、プロジェクトの全体像におけるそれらの位置を理解することは非常に困難です。コミュニケーションとサービス
コミュニケーションやサービスのレベルは会社の規模によって大きく異なります。ただし、一般的な関係は明らかであり、多ければ多いほど問題が大きくなります。- マイクロサービス #47 を実行しているのは誰ですか?
- 互換性のない新しいバージョンのマイクロサービスをデプロイしただけなのでしょうか? これはどこに文書化されていますか?
- 新しい機能をリクエストするには誰に相談すればよいですか?
- Erlang を知っていた唯一の人が会社を去った後、Erlang のマイクロサービスを誰がサポートするのでしょうか?
- 当社のマイクロサービス チームはすべて、異なるプログラミング言語だけでなく、異なるタイムゾーンでも作業しています。これらすべてを正しく調整するにはどうすればよいでしょうか?
GO TO FULL VERSION