JavaRush /Java Blog /Random-JA /Java マイクロサービスのガイド。パート 3: 一般的な質問

Java マイクロサービスのガイド。パート 3: 一般的な質問

Random-JA グループに公開済み
Java マイクロサービスの翻訳と適応: 実践ガイド。ガイドの前の部分: Java のマイクロサービスに固有の問題を、抽象的なものから始めて具体的なライブラリまで見てみましょう。 Java マイクロサービスのガイド。 パート 3: 一般的な質問 - 1

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: 通話は成功し、アカウントは正常に作成されました。
  • 遅延: 電話はつながりましたが、完了するまでに時間がかかりすぎました。
  • エラー。呼び出しが失敗しました。互換性のないリクエストを送信したか、システムが動作していない可能性があります。
どのプログラムでも、成功した場合だけでなく、エラーが発生した場合も処理することが期待されます。マイクロサービスにも同じことが当てはまります。たとえ個々のマイクロサービスのデプロイとリリースを開始したら、デプロイされた API のすべてのバージョンに互換性があることを確認するために特別な労力を費やす必要がある場合でも。 Java マイクロサービスのガイド。 パート 3: 一般質問 - 2注目すべき興味深いケースは遅延のケースです。たとえば、レスポンダーのマイクロサービス ハード ドライブがいっぱいで、応答には 50 ミリ秒かかるのではなく、10 秒かかります。BillingService の応答不能がシステム全体に連鎖し始めるような特定の負荷が発生すると、さらに興味深いことが起こります。わかりやすい例として、レストランのウェイター全員の「ブロック」がゆっくりと調理を開始するところを想像してください。このセクションは明らかに、マイクロサービスの復元力に関するトピックの完全な概要を提供することはできませんが、これは実際には最初のリリース前に対処する必要があり、無視してはいけないものであることを開発者に思い出させるのに役立ちます (経験上、これはより頻繁に発生します)ではありません)。以下に続きます)。レイテンシと耐障害性について考えるのに役立つ人気のあるライブラリは、Netflix の Hystrix です。ドキュメントを使用して、トピックをさらに深く掘り下げてください。

メッセージングの回復力パターン

非同期通信について詳しく見てみましょう。メッセージングに 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 つの潜在的なシナリオがあり、次のような疑問が生じる可能性があります。
  1. 私のメッセージは従業員に届けられ、使用されましたか? それとも紛失したのでしょうか?(ユーザーは請求書を受け取りません)。
  2. 私のメッセージは一度だけ配信されましたか? それとも複数回配信され、一度だけ処理されますか? (ユーザーは複数の請求書を受け取ります)。
  3. 構成: 「交換に正しいルーティング キー/名前を使用しましたか?」から「メッセージ ブローカーは正しく構成および維持されていますか? それともキューがいっぱいですか?」まで。(ユーザーは請求書を受け取りません)。
個々の非同期マイクロサービスの回復力パターンの詳細な説明は、このガイドの範囲を超えています。ただし、正しい方向への標識はあります。さらに、メッセージング技術に依存することになります。例:
  • ActiveMQ のような JMS 実装を使用している場合は、速度を犠牲にして 2 フェーズ (XA) コミットの保証を得ることができます。
  • RabbitMQ を使用している場合は、まずこのチュートリアルを読んでから、確認、フォールト トレランス、メッセージの信頼性全般について慎重に検討してください。
  • おそらく、Active サーバーまたは RabbitMQ サーバーの構成、特にクラスタリングや Docker との組み合わせに精通している人がいるかもしれません (誰か? ;))

Java マイクロサービスにとって最適なソリューションはどのフレームワークでしょうか?

一方で、Spring Bootなどの非常に人気のあるオプションをインストールできます。.jar ファイルの作成が非常に簡単で、Tomcat や Jetty などの組み込み Web サーバーが付属しており、どこでもすばやく実行できます。マイクロサービス アプリケーションの構築に最適です。最近、部分的にリアクティブ プログラミングからインスピレーションを得た、いくつかの特殊なマイクロサービス フレームワーク、KubernetesまたはGraalVMが登場しました。さらに興味深い候補がいくつかあります: QuarkusMicronautVert.xHelidon。最終的には自分で選択する必要がありますが、完全に標準ではない可能性のある推奨事項をいくつか紹介します。 Spring Boot を除いて、すべてのマイクロサービス フレームワークは通常、ほぼ瞬時に起動するため、信じられないほど高速であるとして宣伝されています。 、メモリ使用量が少なく、無限のスケーラビリティ。通常、マーケティング資料には、プラットフォームを巨大な Spring Boot と並べたり、並べて見せたりする印象的なグラフィックが掲載されています。これにより、理論的には、読み込みに数分かかることがあるレガシー プロジェクトをサポートする開発者の神経が解放されます。または、クラウドで作業し、現在必要な数のマイクロコンテナを 50 ミリ秒以内に起動/停止したい開発者。 Java マイクロサービスのガイド。 パート 3: 一般的な質問 - 3ただし、問題は、これらの (人為的な) ベアメタルの起動時間と再デプロイ時間は、プロジェクト全体の成功にはほとんど寄与しないことです。少なくとも、強力なフレームワーク インフラストラクチャ、強力なドキュメント、コミュニティ、および強力な開発者のスキルよりも影響力ははるかに小さいです。したがって、次のように考える方がよいでしょう: これまでのところ:
  • ORM を蔓延させて、単純なワークフローに対して何百ものクエリを生成します。
  • 適度に複雑なモノリスを実行するには、無限のギガバイトが必要です。
  • 非常に多くのコードがあり、複雑さが非常に高いため (ここでは Hibernate のような潜在的なスロースターターについては話していません)、アプリケーションのロードに数分かかります。
この場合、mycoservice の問題 (ネットワーク復元力、メッセージング、DevOps、インフラストラクチャ) を追加すると、空の Hello, world を読み込むよりもプロジェクトに大きな影響を与えることになります。また、開発中のホット再デプロイメントの場合は、 JRebelDCEVMなどのソリューションが使用される可能性があります。Simon Brown の言葉をもう一度引用しましょう。「人々が (高速かつ効率的な) モノリスを構築できない場合、構造に関係なく、(高速かつ効率的な) マイクロサービスを構築するのは困難になります。」したがって、フレームワークは賢明に選択してください。

同期 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 は従来の「スマート」ブローカーとは言えません。代わりに、これは比較的「愚かな」メッセージ ストア (ログ ファイル) であり、賢明なコンシューマが処理する必要があります。
RabbitMQ (またはその他の従来のメッセージ ブローカー一般) または Kafka をいつ使用するべきかをより深く理解するには、出発点としてこの Pivotal の投稿を参照してください。一般に、メッセージング ブローカーを選択するときは、人為的なパフォーマンス上の理由を無視するようにしてください。かつて、チームやオンライン コミュニティは、RabbitMQ がどれほど速いか、ActiveMQ がどれほど遅いかについて常に議論していた時期がありました。現在、RabbitMQ に関しても同じ議論が行われており、1 秒あたり 2 万から 3 万のメッセージが発生すると動作が遅いと言われています。Kafka は 1 秒あたり 10 万メッセージを記録します。率直に言って、そのような比較は温かいものと柔らかいものを比較するようなものです。さらに、どちらの場合でも、スループット値は、たとえばアリババ グループの低から中程度の範囲にある可能性があります。ただし、実際にはこの規模 (1 分間に数百万件のメッセージ) のプロジェクトに遭遇することはほとんどありません。それらは間違いなく存在し、問題を抱えているでしょう。他の 99% の「通常の」Java ビジネス プロジェクトとは異なります。だから、ファッションや誇大宣伝には注意を払わないでください。賢明に選択してください。

マイクロサービスのテストにはどのようなライブラリを使用できますか?

それはあなたのスタックに依存します。Spring エコシステムをデプロイしている場合は、フレームワークの特定のツールを使用することが賢明です。JavaEE がArquillianのようなものである場合。Docker と非常に優れたTestcontainersライブラリを検討してみる価値があるかもしれません。これは、特にローカル開発または統合テスト用に Oracle データベースを簡単かつ迅速にセットアップするのに役立ちます。HTTP サーバー全体の模擬テストについては、Wiremockを確認してください。非同期メッセージングをテストするには、ActiveMQ または RabbitMQ を実装してから、Awaitility DSLを使用してテストを作成してみてください。さらに、すべての通常のツール ( JunitAssertJ用のTestNG、およびMockito )が使用されます。これは完全なリストではないことに注意してください。ここでお気に入りのツールが見つからない場合は、コメント欄に投稿してください。

すべての Java マイクロサービスのログ記録を有効にするにはどうすればよいですか?

マイクロサービスの場合のロギングは、興味深いですがかなり複雑なトピックです。less または grep コマンドで操作できる 1 つのログ ファイルの代わりに、n 個のログ ファイルが存在することになり、それらが散在しすぎないようにする必要があります。ロギング エコシステムの機能については、この記事(英語) で詳しく説明されています。必ず読んで、「マイクロサービスの観点から見た集中ログ」セクションに注意してください。実際には、さまざまなアプローチが考えられます。システム管理者は、さまざまなサーバーからログ ファイルを収集して 1 つのログ ファイルに結合し、ダウンロード用に FTP サーバーに置く特定のスクリプトを作成します。cat/grep/unig/sort の組み合わせを並列 SSH セッションで実行します。これはまさに Amazon AWS が行っていることなので、マネージャーに知らせることができます。GraylogELK Stack (Elasticsearch、Logstash、Kibana)などのツールを使用する

マイクロサービスはどのようにして互いを見つけるのでしょうか?

これまで、マイクロサービスは相互に認識しており、対応する IPS を認識していると想定してきました。静的構成について話しましょう。したがって、バンキング モノリス [ip = 192.168.200.1] は、プロパティ ファイルにハードコードされているリスク サーバー [ip = 192.168.200.2] と通信する必要があることを認識しています。ただし、物事をより動的にすることもできます。
  • application.properties ファイルをマイクロサービスにデプロイする代わりに、すべてのマイクロサービスが構成を取得するクラウドベースの構成サーバーを使用します。
  • サービス インスタンスはその場所を動的に変更できるため、サービスが存在する場所、IP が何であるか、およびそれらをルーティングする方法を認識しているサービスに注目する価値があります。
  • すべてが動的になると、リーダーの自動選出などの新しい問題が発生します。たとえば、タスクを 2 回処理しないように特定のタスクに取り組むマスターは誰ですか? リーダーが失敗したとき、誰が代わりをするのでしょうか?交換はどのような基準に基づいて行われますか?
一般的に言えば、これはマイクロサービス オーケストレーションと呼ばれるものであり、これも底なしのトピックです。EurekaZookeeperなどの図書館は、利用可能なサービスを示すことでこれらの問題を「解決」しようとしています。一方で、さらに複雑さが増します。ZooKeeper をインストールしたことがある方に質問してください。

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 回の追加呼び出し (ページングの実装に応じて) を行う必要があります。 Java マイクロサービスのガイド。 パート 3: 一般質問 - 4そして、これは実際の (!) プロジェクトから取られたものではあるものの、単なる単純な例にすぎませんが、次の問題を示しています。スーパーマーケットが非常に人気になっているということです。なぜなら、彼らがあれば、野菜、レモネード、冷凍ピザ、トイレットペーパーを買うために10か所の異なる場所に行く必要がないからです。代わりに、1 か所に行くほうが簡単かつ迅速です。フロントエンド開発者やマイクロサービス開発者にも同じことが当てはまります。

経営陣の期待

開発者は互いに完全に独立して、それぞれが独自のマイクロサービスで作業できるようになったため、経営者は、(包括的な) プロジェクトのために無限の数の開発者を雇用する必要があると誤解しています。最後 (起動直前) に必要な統合作業はほんの少しだけです。 Java マイクロサービスのガイド。 パート 3: 一般的な質問 - 5実際、このアプローチには非常に問題があります。次の段落では、その理由を説明していきます。

「より小さな作品」は「より良い作品」と同じではありません

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 のマイクロサービスを誰がサポートするのでしょうか?
  • 当社のマイクロサービス チームはすべて、異なるプログラミング言語だけでなく、異なるタイムゾーンでも作業しています。これらすべてを正しく調整するにはどうすればよいでしょうか?
Java マイクロサービスのガイド。 パート 3: 一般的な質問 - 6重要な点は、DevOps と同様、大企業 (おそらくは国際的な企業) におけるマイクロサービスへの本格的なアプローチには、さらに多くの通信問題が伴うということです。そして、企業はこれに真剣に備える必要があります。

結論

この記事を読むと、著者はマイクロサービスの熱烈な反対者であると思われるかもしれません。これは完全に真実ではありません。私は基本的に、新しいテクノロジーを求める激しい競争の中でほとんどの人が注目していない点を強調したいのです。

マイクロサービスかモノリスか?

Java マイクロサービスをいつでもどこでも使用できるのは、極端な例です。もう 1 つは、モノリス内の何百もの古き良き Maven モジュールのようなものであることが判明しました。あなたの仕事は、適切なバランスを見つけることです。これは特に新しいプロジェクトに当てはまります。20 個のクラウド対応マイクロサービスから始めるのではなく、より保守的な「モノリシック」アプローチを採用し、優れた Maven モジュールの数を減らして作成することを妨げるものはありません。

マイクロサービスはさらに複雑さを生み出します

マイクロサービスの数が増え、実際に強力な DevOps が少なくなるほど (Ansible スクリプトをいくつか実行したり Heroku にデプロイしたりすることはカウントされません!)、プロセスの後半でより多くの問題が発生することに注意してください。Java マイクロサービスに関する一般的な質問に特化したこのガイドのセクションを最後まで読むだけでも、非常に面倒な作業です。これらすべてのインフラストラクチャの問題に対する解決策の実装についてよく考えてみると、それはもはやビジネス プログラミング (報酬を得る仕事) がすべてではなく、むしろより多くのテクノロジーをさらに多くのテクノロジーに修正することが重要であることに突然気づくでしょう。Shiva Prasad Reddy は自身のブログでこのことを完璧に要約しました: 「チームが時間の 70% をこの最新のインフラストラクチャとの格闘に費やし、実際のビジネス ロジックを実行するのに残された時間は 30% だけであることが、どれほどひどいことか想像もつきません。シヴァ ・プラサド・レディ

Java マイクロサービスを作成する価値はありますか?

この質問に答えるために、非常に生意気な Google インタビュー風のティーザーでこの記事を終えたいと思います。この質問に対する答えを経験から知っている場合は、たとえそれがマイクロサービスと何の関係もないと思われる場合でも、マイクロサービスのアプローチを受け入れる準備ができている可能性があります。

シナリオ

最小のHetzner専用サーバー上で Java モノリスが単独で実行されていると想像してください。同じことがデータベース サーバーにも当てはまり、同様のHetznerマシン上で実行されます。また、Java モノリスがユーザー登録などのワークフローを処理でき、ワークフローごとに数百のデータベース クエリを作成するのではなく、より適切な数 (10 未満) を作成すると仮定します。

質問

Java モノリス (接続プール) はデータベース サーバー上でいくつのデータベース接続を開く必要がありますか? 何故ですか?あなたのモノリスは(およそ)何人の同時アクティブ ユーザーを拡張できると思いますか?

答え

これらの質問に対する答えをコメント欄に残してください。皆さんの回答を楽しみにしています。 Java マイクロサービスのガイド。 パート 3: 一般的な質問 - 8さあ、決心してください。最後まで読んでいただき、ありがとうございました!
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION