リボンの負荷分散
1.1. 負荷分散の原理
Spring Cloud の最下層では、実際にはリボンと呼ばれるコンポーネントを使用して負荷分散機能を実装しています。
では、送信したリクエストは明らかに http://userservice/user/1 でしたが、なぜ http://localhost:8081 になったのでしょうか?
1.2. ソースコードの追跡
なぜサービス名を入力するだけでアクセスできるのでしょうか?また、事前に IP とポートを取得する必要があります。
どうやら誰かがサービス名に基づいてサービス インスタンスの IP とポートを取得するのを手伝ってくれたようです。つまりLoadBalancerInterceptor
、このクラスは RestTemplate リクエストをインターセプトし、サービス ID に基づいて Eureka からサービス リストを取得し、負荷分散アルゴリズムを使用して実際のサービス アドレス情報を取得し、サービス ID を置き換えます。
私たちはソースコードの追跡を実施します。
1)ロードバランサーインターセポート
ここでの intercept メソッドがユーザーの HttpRequest リクエストをインターセプトし、いくつかのことを実行することがわかります。
request.getURI()
: リクエスト URI を取得します。この場合は http://user-service/user/8originalUri.getHost()
: URI パスのホスト名を取得します。これは実際にはサービス ID です。user-service
this.loadBalancer.execute()
: サービス ID とユーザー リクエストを処理します。
タイプは次のとおりthis.loadBalancer
です。引き続きフォローしてみましょう。LoadBalancerClient
2)ロードバランサークライアント
引き続き実行メソッドに従います。
コードは次のようなものです:
- getLoadBalancer(serviceId): サービス ID に基づいて ILoadBalancer を取得します。ILoadBalancer はサービス ID を取得して eureka からサービス リストを取得し、保存します。
- getServer(loadBalancer): 組み込みの負荷分散アルゴリズムを使用して、サービス リストから 1 つを選択します。この例では、ポート 8082 のサービスが取得されていることがわかります。
解放された後、再度アクセスして追跡したところ、8081 を取得していることがわかりました。
案の定、負荷分散は達成されました。
3) 負荷分散戦略 IRule
getServer
先ほどのコードでは、サービスの取得で負荷分散を実行するメソッドが使用されていることがわかります。
引き続きフォローアップしてみましょう:
ソース コードのchooseServer メソッドをトレースし続けると、次のコードが見つかりました。
このルールが誰であるかを見てみましょう:
ここでのルールのデフォルト値は one ですRoundRobinRule
。クラスの紹介を参照してください。
これが投票の意味ではないでしょうか?
この時点で、負荷分散プロセス全体を明確に理解できました。
4) まとめ
SpringCloudRibbon の最下層はインターセプターを使用して、RestTemplate によって送信されたリクエストをインターセプトし、アドレスを変更します。画像でまとめてみましょう:
基本的なプロセスは次のとおりです。
- RestTemplate リクエストをインターセプト http://userservice/user/1
- ibbonLoadBalancerClient は、リクエスト URL からサービス名を取得します。これは user-service です。
- DynamicServerListLoadBalancer は、ユーザー サービスに基づいて eureka からサービス リストを取得します
- eureka はリスト、localhost:8081、localhost:8082 を返します。
- IRule は組み込みの負荷分散ルールを利用し、リストから 1 つ (localhost:8081 など) を選択します。
- ibbonLoadBalancerClient はリクエスト アドレスを変更し、userservice を localhost:8081 に置き換え、http://localhost:8081/user/1 を取得して、実際のリクエストを開始します。
1.3. 負荷分散戦略
1.3.1. 負荷分散戦略
負荷分散ルールは IRule インターフェイスで定義され、IRule にはさまざまな実装クラスがあります。
さまざまなルールの意味は次のとおりです。
組み込みの負荷分散ルールクラス | ルールの説明 |
---|---|
ラウンドロビンルール | サービス リストをポーリングしてサーバーを選択するだけです。これは、リボンのデフォルトの負荷分散ルールです。 |
可用性フィルタリングルール | 次の 2 種類のサーバーは無視してください。 (1) デフォルトでは、このサーバーが 3 回接続に失敗すると、このサーバーは「短絡」状態に設定されます。短絡状態は 30 秒間続きますが、再度接続に失敗すると、短絡時間は幾何級数的に増加します。(2) 同時実行性が高すぎるサーバー。サーバーへの同時接続の数が多すぎる場合、AvailabilityFilteringRule ルールが設定されているクライアントもそれを無視します。同時接続数の上限は、クライアントの ..ActiveConnectionsLimit プロパティによって構成できます。 |
WeightedResponseTimeRule | 各サーバーに重み値を与えます。サーバーの応答時間が長いほど、サーバーの重みは小さくなります。このルールはサーバーをランダムに選択し、この重み値はサーバーの選択に影響します。 |
ゾーン回避ルール | サーバーの選択は、その地域で利用可能なサーバーに基づいて行われます。ゾーンを使用してサーバーを分類します。このゾーンは、コンピューター室、ラックなどとして理解できます。次に、ゾーン内の複数のサービスをポーリングします。 |
BestAvailableルール | ショートサーキットしているサーバーを無視し、同時実行数が低いサーバーを選択します。 |
ランダムルール | 利用可能なサーバーをランダムに選択します。 |
再試行ルール | リトライ機構の選択ロジック |
デフォルトの実装は、ポーリング スキームである ZoneAvoidanceRule です。
1.3.2. カスタマイズされた負荷分散戦略
負荷分散ルールは、次の 2 つの方法で IRule 実装を定義することで変更できます。
- コード メソッド: order-service の OrderApplication クラスで、新しい IRule を定義します。
@Bean
public IRule randomRule(){
return new RandomRule();
}
- 構成ファイルによる方法: order-service の application.yml ファイルで、新しい構成を追加すると、ルールを変更することもできます。
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
通常、デフォルトの負荷分散ルールは変更せずに使用されることに注意してください。
1.4.ハングリーロード
リボンはデフォルトで遅延読み込みを使用します。つまり、LoadBalanceClient は最初のアクセスまで作成されず、要求時間は非常に長くなります。
プロジェクトの開始時にハングリー ローディングが作成され、最初のアクセス時間が短縮されます。次の構成を通じてハングリー ローディングを有効にします。
ribbon:
eager-load:
enabled: true
clients: userservice
Dark Horse Programmer から編集された研究ノート