[SpringCloud] リボン負荷分散に基づく Eureka コールリンクプロセス分析

序文

マイクロサービス間の相互呼び出しに基づいて、サービス間の呼び出しは、マルチインスタンス サービスの下でインスタンスを呼び出す形式になります。そして、これには負荷分散テクノロジーの使用が必要です。開発者の場合、@LoadBalance アノテーションを使用して負荷分散を有効にすることができます。このような単純な操作の最下層がどのようなものかを知りたいと思うこともあると思います。

1. お電話フォーム

SpringCloud は Eureka を統合し、負荷分散を実装する」に基づいて、小規模な実験を実施し、実行中のプログラムをデバッグし、リクエストを開始できます。郵便配達員を通じて、サービス A はサービス B をリモートで呼び出します。デバッグにより、送信された URL が http://user-service/user/1 であることがわかりました。これが A がサービス B を呼び出す方法であることは疑いの余地がありません。 パスに問題があるため、リクエストを送信できないことがわかりました。パス内のパラメーター user-service を観察すると、それがサービス B のサービス名であることがわかります。では、サービス A からサービス A に「サービス名 - インターフェイス パス - パラメーター」の形式でリクエストを送信すると、なぜ正常に応答できるのでしょうか。サービスB? 統合された負荷分散プロセスと組み合わせると、リボンが機能する必要があります
ここに画像の説明を挿入します

ここに画像の説明を挿入します

2.ロードバランサーインターセプター

ロード バランシングの前提は、特定の URL を渡すことではありません。リボンは何らかの解析を実行し、サービス名を通じてサービスの下のインスタンス リストを取得し、それによって Eureka-Server のサービス レジストリをプルして、リクエストを転送し、指定されたインスタンスにマップします。
フロントエンドとバックエンドを分離していた Web 開発の経験と組み合わせると、バックエンドは多くの場合、インターセプタでフロントエンドからのリクエストをインターセプトし、リクエストに対していくつかの操作を実行します。検証、スプライシング、認証...そして呼び出しとして、送信側が送信したリクエストと受信側が受信したリクエストに一貫性がありません。リクエストをインターセプトしてリクエストを変換するインターセプターのようなものはありますか?
答えは避けられません。それは誰ですか - LoadBalancerInterceptor
ここに画像の説明を挿入します
見てわかるのは、彼が ClientHttpRequestInterceptor インターフェイスを実装しているということです。具体的な使用方法の詳細については、宣言を直接参照してください。インターフェイス内。メソッド
インターフェイスが intercept() メソッドを宣言し、HttpRequest パラメータを受け入れてクライアントの http リクエストをインターセプトし、リクエストの本文を変更することが直感的にわかります。 URL 変更に対する答えはここで明らかになります。したがって、メソッドの最下層はどのように実装されるのか:

3. 負荷分散プロセスの分析

3.1 呼び出しフローチャート

ソース コードをデバッグする前に、ソース コード内の呼び出しリンクの全体的なフローチャート (手の図) を見てみましょう。
ここに画像の説明を挿入します
要約すると、次のとおりです。 -read service-pull サービス リスト - 選択ルール - サービス インスタンスを返す

3.2 intercept()方法

デバッグを開始しましょう:
1. サービス間の呼び出し関係を引き起こすリクエストを送信すると、呼び出しリクエストはまず に渡されます。インターセプターのインターセプト メソッドでは、
ここに画像の説明を挿入します
2 の送信と一貫性があることがわかります。 2. 実行を続行し、リクエストの解析を開始し、 request —— getHost() メソッドを通じてホスト アドレス (サービスの名前) を取得します。
ここに画像の説明を挿入します

3.3execute()メソッド

3. リボンが負荷分散処理を開始します
ここに画像の説明を挿入します
4. 2 回入力した後、execute() メソッドに入り、渡されたサービス名がサービスとして getLoadBalance() に入力されていることを確認します。 Id. ) メソッドを実行し、ILoadbalance インターフェイス オブジェクトを取得しました。これには、多くの情報がカプセル化されています:
ここに画像の説明を挿入します
ここで、値を覚えておいてください。サービス インスタンス ID:host.docker.internal:8084、これは Eureka クライアントによって受信されるインスタンス情報です

3.4 getServer() メソッド

5. インターフェイス オブジェクトがパラメータとして getServer() メソッドに渡され、サーバー オブジェクトが取得されてメソッドに入力されます。サーバーのルールまたは条件を指定するために、Object 型のオブジェクトが同時に渡されたことが判明しましたが、これまでのところ、このパラメータは null として渡されています。つまり、loadBalancer.chooseServer() メソッドは「デフォルト」メソッド。選択してください
ここに画像の説明を挿入します

3.4 サブクラスのchooseServer()メソッド

6.chooseServer() メソッドに再度ステップインし、これが BaseLoadBalancer というクラスの下で書き直された親クラス メソッドであることを確認します (このクラスはロード バランサーの特定の実装であり、後ほど詳しく分析します)< /span>
現時点で判断できるのは、getLoadBalancerStats().getAvailableZones().size() <= 1 が TRUE
ここに画像の説明を挿入します

3.5 getLoadBalancerStats().getAvailableZones().size() <= 1

式の場合: getLoadBalancerStats().getAvailableZones().size() <= 1 分析用
BaseLoadBalancer クラスでは、抽象クラス AbstractLoadBalancer を継承していることがわかります。 getLoadBalancerStats( ) 抽象メソッドをオーバーライドし、ロードバランサー統計情報コレクション LoadBalancerStats
ここに画像の説明を挿入します
ここに画像の説明を挿入します
を取得します。LoadBalancerStats にカプセル化された情報には、ConcurrentHashMap タイプのコレクション属性があります。 /a >

volatile Map<String, List<? extends Server>> upServerListZoneMap = new ConcurrentHashMap<String, List<? extends Server>>();

は、 利用可能なサービスのリストを保存するために使用されます。このコレクションの各エントリはリージョンを表します。キーはリージョン名と値は、このゾーンで使用可能なサーバーのリストです。
ここに画像の説明を挿入します
後続の .getAvailableZones() メソッドは、この属性値のすべてのキー、つまり利用可能なサービス エリアを取得し、判定用の Set コレクションとして返します。
ここに画像の説明を挿入します
明らかに、ここで getLoadBalancerStats().getAvailableZones().size() <= 1 が true であり、親クラスのchooseServer() メソッドが後で呼び出されるというさらなる証拠が得られます

3.6 親クラスのChooseServer()メソッド

7. 親クラスのchooseServer()メソッドにステップインすると、最終的にServerタイプのオブジェクトが返されることがわかります(これは特定のサービス・インスタンス情報である必要があります)。
ここに画像の説明を挿入します

3.7 IRule インターフェースでの例

がルール変数をトレースしたところ、それが IRule インターフェイスのインスタンスであることがわかりました。IRule インターフェイスは、負荷分散のためのルールを提供するインターフェイスです
ここに画像の説明を挿入します
。以下に多数のルール実装があります。このインターフェイス、およびデフォルトのルール方法はポーリング スケジューリングです:
ここに画像の説明を挿入します
ただし、上の図でデバッグする場合、灰色のルール変数の右側の色はrule:RandomRule@12045これは、IRule タイプ Bean を構成して負荷分散ルールを指定したためです。

    @Bean
    public IRule randomRule() {
    
    
        return new RandomRule();
    }

コメントアウトしている限り、プログラムはデフォルトのルールを使用し続けますRoundRobinRule

3.8 最後のchoose()メソッド - サーバーを返す

8. IRule インターフェイスのルール インスタンスを理解した後、最後に呼び出されるchoose() メソッドを見てみましょう。これはデフォルトのルールであるため、プロセスに従い、RoundRobinRule ルール実装にchoose メソッドを入力します (実際、IRule インターフェイスのすべてのルール実装クラスにはchoose メソッドがあります)
ここに画像の説明を挿入します
実装 ILoadBalancerインターフェイスのロード バランサー オブジェクトがパラメーターとしてメソッドに渡され、キーはデフォルトです。ランダムに選択するためのウォームアップを開始します。

3.9choose()メソッドの内部分析

9. while ループに入り、使用可能なサーバーが見つかるまでサーバーの選択を続けます。次に、スレッドが中断されているかどうかを判断します。中断された場合は、null が直接返されます。
ここに画像の説明を挿入します
この状況は依然として非常に頻繁に発生しますが、この小さな設計により多くの不要な計算が削減され、プログラムの動作効率が向上することがわかります。
次に、2 つのサービス リストをそれぞれ取得します。 ここに画像の説明を挿入します
リストから 1 つを選択します。
ここに画像の説明を挿入します
操作を実行して判断します。選択< /span>ここに画像の説明を挿入します
最後に、サーバー インスタンスはchooseServer() メソッドに正常に返されました。サービス イニシエーターはリボン経由で http://user-service/user リクエストを送信し、最後に localhost:8084 をポーリングしました。サービス インスタンス

4. イースターエッグ

現在、多くの企業が Eureka の代わりに Nacos を使用しています。これは、次の状況のように、サービス リストの変更を検出できるほど感度が低く、オフライン サービスを検出するには遅すぎるためです。< a i=1>サービス インスタンスは約 1 分間オフラインになっていますが、オフライン サービスはまだ利用可能なサービス リスト (upList) に読み込まれています。実際、これはリボンのせいではなく、すべて Eureka のせいです。< a i=2> この状況についてはイースターエッグを残して、それについては次回話します~
ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/weixin_57535055/article/details/134449104