Spring Cloud(6):リボン負荷分散サービスの呼び出し

1。概要

Spring Cloud Ribbonは、Netflixリボンに基づくクライアント負荷分散ツールのセットです。

簡単に言えば、リボンはNetflixによってリリースされたオープンソースプロジェクトであり、その主な機能はクライアント側の負荷分散アルゴリズムとサービス呼び出しを提供することです。リボンクライアントコンポーネントは、接続タイムアウト、再試行などの一連の完全な構成アイテムを提供します。簡単に言えば、構成ファイルに負荷分散(略してLB)の背後にあるすべてのマシンをリストすることです。リボンは、特定のルール(単純なポーリング、ランダム接続など)に基づいてこれらのマシンを自動的に接続するのに役立ちます。簡単リボンを使用して、カスタムの負荷分散アルゴリズムを実装します。

公式ウェブサイト情報:https://github.com/Netflix/ribbon/wiki/Getting-Started

2. LB(負荷分散)

2.1LBロードバランシングとは

簡単に言えば、システムのHA(高可用性)を実現するために、ユーザーの要求は複数のサーバーに均等に分散されます。一般的な負荷分散には、ソフトウェアnginx、LVS、ハードウェアF5などが含まれます。

2.2リボンローカルゲスト負荷分散クライアントとnginxサーバー負荷分散の違い

Nginxはサーバーの負荷分散です。すべてのクライアントリクエストはnginxに渡され、nginxは転送リクエストを実装します。つまり、負荷分散はサーバーによって実装されます。

リボンローカル負荷分散:マイクロサービスインターフェイスを呼び出すと、登録情報サービスリストがレジストリリストから取得され、JVMにローカルにキャッシュされるため、RPCリモートサービス呼び出しテクノロジがローカルに実装されます。

集中型LB
とは、サービスのコンシューマーとプロバイダーの間で独立したLBファシリティ(F5などのハードウェアまたはnginxなどのソフトウェア)を使用することを指します。ファシリティは、特定の戦略プロバイダーを介してサービスへのアクセス要求を転送する責任があります。

インプロセスLB
は、LBロジックをコンシューマーに統合します。コンシューマーは、サービスレジストリまたは使用可能なアドレスから適切なサーバーを選択します。リボンは、単なるクラスライブラリであるインプロセスLBに属します。コンシューマープロセスに統合され、消費者は、彼を通じてサービスプロバイダーのアドレスを取得します。

3.リボンの負荷分散

3.1アーキテクチャの説明

ここに画像の説明を挿入します
作業中のリボンは2つのステップに分かれています。

  • 最初のステップはEurekaサーバーを選択することです。彼は、同じエリアで負荷の少ないサーバーを選択することを好みます。
  • 2番目の部分では、ユーザーが指定した戦略に従ってサーバーが取得したサービスのリストからアドレスを選択します。
    その中で、リボンは、ポーリング、ランダム、応答時間に基づく重み付けなど、さまざまな戦略を提供します。

概要:リボンは実際にはソフトロードバランシングのクライアントコンポーネントであり、リクエストを必要とする他のクライアントと組み合わせて使用​​できます。eurekaとの組み合わせはほんの一例です。

3.2RestTemplateの使用

https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

getForObjectメソッド/ getForEntityメソッド
ここに画像の説明を挿入します

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

3.3リボンコアコンポーネントIRule

IRule:特定のアルゴリズムに従ってサービスのリストからアクセスするサービスを選択します

  • com.netflix.loadbalancer.RoundRobinRule:ポーリング
  • com.netflix.loadbalancer.RandomRule:ランダム
  • com.netflix.loadbalancer.RetryRule:最初にRoundRobinRule戦略に従ってサービスを取得します。サービスが失敗した場合、指定された時間内に再試行します
  • WeightedResponseTimeRule:RoundRobinRuleの拡張であり、応答速度が速いほど、インスタンス選択の重みが大きくなり、選択が容易になります。
  • BestAvailableRule:最初に、複数のアクセス障害が原因でサーキットブレーカーのトリップ状態にあるサービスを除外し、次に同時実行性が最も少ないサービスを選択します。
  • AvailabilityFilteringRule:最初に失敗したインスタンスを除外し、次に同時実行性の低いインスタンスを選択します
  • ZoneAvoidanceRule:デフォルトのルールであるコンポジットは、サーバーが配置されているエリアのパフォーマンスと、サーバーを選択するためのサーバーの可用性を判断します。

交換方法
modifycloud-consumer-order80
構成の詳細に注意してください。
ここに画像の説明を挿入します
ここに画像の説明を挿入します

  • 新しいパッケージ
    ここに画像の説明を挿入します
  • 新しいMyselfRuleクラスを作成します
package com.lele.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: lele
 * @date: 2021/3/15 7:12
 * @description:
 */
@Configuration
public class MySelfRule {
    
    

    @Bean
    public IRule myRule() {
    
    
        return new RandomRule(); // 定义为随机
    }
}
  • コンシューマー80のメインスタートアップクラスに@RibbonClient
    ここに画像の説明を挿入します
    ブラウザーアクセスを追加します:http:// localhost / Consumer / Payment / get / 1

4.リボン負荷分散アルゴリズム

4.1原則

負荷分散アルゴリズム:RESTインターフェースへの要求数%サーバークラスターの総数=実際のコールサーバーロケーションインデックス(RESTインターフェースの数は各再起動後に1から始まります)

List instances = discoveryClient.getInstances(“CLOUD-PAYMENT-SERVICE”);

List[0] instances = 127.0.0.1:8001
List[1] instances = 127.0.0.1:8002

8001と8002は1つのクラスターに結合され、合計2台のマシンがあり、クラスターの総数は2です。ポーリングアルゴリズムの原則によると、次のようになります。

リクエストの総数が1の場合、1%2 = 1は添え字の位置1に対応し、取得したサーバーアドレスは127.0.0.1:8002
です。リクエストの総数が2の場合、2%2 = 0はに対応します。添え字位置0、取得されたサーバーアドレスは
、リクエストの総数が3の場合、127.0.0.1:8001であり、3%2 = 1は添え字位置1に対応し、取得されたサーバーアドレスは127.0.0.1です。 :8002
ラベルの位置が0の場合、得られたサーバアドレスは127.0.0.1:8001とき要求の合計数は、4である4%2 = 0に相当次へ
...と
そうで

4.2手書きポーリングアルゴリズム

  • 7001/7002クラスターの起動

  • 8001/8002マイクロサービスの変革
    ここに画像の説明を挿入します
    ここに画像の説明を挿入します

  • 80オーダーのマイクロサービス変換:

    • ApplicationContextBeanは@LoadBalancedを削除します
      ここに画像の説明を挿入します

    • LoadBalancerインターフェース
      ここに画像の説明を挿入します

    • MyLB

      package com.lele.springcloud.lb;
      
      import org.springframework.cloud.client.ServiceInstance;
      import org.springframework.stereotype.Component;
      
      import java.util.List;
      import java.util.concurrent.atomic.AtomicInteger;
      
      /**
       * @author: lele
       * @date: 2021/3/16 7:27
       * @description:
       */
      @Component
      public class MyLB implements LoadBalancer {
              
              
      
          private AtomicInteger atomicInteger = new AtomicInteger(0);
      
          public final int getAndIncrement() {
              
              
              int current;
              int next;
              do {
              
              
                  current = this.atomicInteger.get();
                  next = current >= 2147483647 ? 0 : current + 1;
              } while (!this.atomicInteger.compareAndSet(current,  next));
              System.out.println("*****第几次访问,次数next:"+next);
              return next;
          }
      
          @Override
          public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
              
              
              int index = getAndIncrement() % serviceInstances.size();
              return serviceInstances.get(index);
          }
      }
      
      
  • 80 OrderController

package com.lele.springcloud.controller;

import com.lele.springcloud.entities.CommonResult;
import com.lele.springcloud.entities.Payment;
import com.lele.springcloud.lb.LoadBalancer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.net.URI;
import java.util.List;

/**
 * @author: lele
 * @date: 2021/3/1 21:33
 * @description:
 */
@RestController
@Slf4j
public class OrderController {
    
    

//    public static final String PAYMENT_URL = "http://localhost:8001";
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private LoadBalancer loadBalancer;

    @Resource
    private DiscoveryClient discoveryClient;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
    
    
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
    
    
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }

    @GetMapping("/consumer/payment/getForEntity/{id}")
    public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    
    
        ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);

        if (entity.getStatusCode().is2xxSuccessful()) {
    
    
            return entity.getBody();
        } else {
    
    
            return new CommonResult<>(444, "操作失败");
        }
    }

    @GetMapping(value = "/consumer/payment/lb")
    public String getPaymentLB() {
    
    
        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        if (instances == null || instances.size() <= 0) {
    
    
            return null;
        }

        ServiceInstance serviceInstance = loadBalancer.instances(instances);

        URI uri = serviceInstance.getUri();

        return restTemplate.getForObject(uri+"/payment/lb", String.class);
    }

}

  • T试
    http:// localhost / Consumer / Payment / lb

おすすめ

転載: blog.csdn.net/houwanle/article/details/114789056
おすすめ