SpringCloudの毎日のデモを学ぶ
リボンとは?
Spring Cloud Ribbonは、Netflix Ribbonに基づくクライアントロードバランシングツールのセットです。
リボンは、Netflixによってリリースされたオープンソースプロジェクトであり、その主な機能は、クライアントソフトウェアの負荷分散アルゴリズムとサービス呼び出しを提供することです。リボンクライアントコンポーネントは、接続タイムアウト、再試行などの一連の完璧な構成アイテムを提供します。簡単に言えば、ロードバランサー(略してLB)の背後にあるすべてのマシンを構成ファイルにリストすることです。リボンは、特定のルール(単純なポーリング、ランダム接続など)に基づいてこれらのマシンを自動的に接続するのに役立ちます。リボンを使用してカスタムロードバランシングアルゴリズムを実装するのは簡単です。
LBロードバランス(ロードバランス)
簡単に言うと、ユーザーの要求は複数のサービスに均等に分散され、システムのHA(高可用性)を実現します。一般的な負荷分散には、ソフトウェアNginx、LVS、ハードウェアF5などが含まれます。
- 一元化されたB
は、サービスのコンシューマーとプロバイダーの間で独立したLB機能(F5などのハードウェア、またはnginxなどのソフトウェア)が使用されることを意味します。この機能は、特定の戦略を通じてサービスにアクセス要求を転送する責任があります。プロバイダー - インプロセスLB
はLBロジックをコンシューマーに統合し、コンシューマーはサービス登録センターから利用可能なアドレスを学習し、これらのアドレスから適切なサーバーを選択します。リボンはインプロセスLBに属し、それは単なるコンシューマープロセスに統合されたクラスライブラリであり、コンシューマーはそれを通じてサービスプロバイダーのアドレスを取得します。
リボンは、負荷分散+ RestTemplate呼び出しであり、最終的にRPCのリモート呼び出しを実現します。
リボンアーキテクチャ
spring-cloud-starter-netflix-eureka-clientはリボンを統合しているため、依存関係を追加せずにリボンを使用できます
リボンの負荷分散メカニズムIRule
デフォルトのポーリングメカニズム
リボンの負荷分散アルゴリズムを指定する
注:このカスタム構成クラスは、@ ComponentScanによってスキャンされた現在のパッケージおよびサブパッケージの下に配置できません。それ以外の場合、カスタム構成クラスはすべてのリボンクライアントによって共有され、特別なカスタマイズの目的を達成できません。
/*
配置自定义负载均衡算法,注意不能与主启动类所在包相同(为避免@ComponentScan)
*/
@Configuration
public class MyselfRule {
@Bean
public IRule myRule(){
// 负载均衡算法:随机
return new RandomRule();
}
}
メインのスタートアップクラスに注釈を付けます:@RibbonClient(name = "CLOUD-PAYMENT-SERVICE"、configuration = MyselfRule.class)
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration= MyselfRule.class)
public class OrderMain80 {
public static void main(String args[]) {
SpringApplication.run(OrderMain80.class, args);
}
}
自己実装型負荷分散アルゴリズム:ポーリング
ポーリングアルゴリズムの原理
- 残りのインターフェイスでの要求の数%サーバークラスターの総数=実際のサーバーの場所のインデックス
- サーバーが再起動するたびに、残りのインターフェイスの数が1から始まります
ポーリングアルゴリズムのソースコード分析
スピンロックとCASによる並行性戦略
- serverCount:CLOUD-PAYMENT-SERVICEサービスクラスター(payment8001、payment8002)のインスタンスの数など、サービスクラスターに含まれるインスタンスの数は2です。
- nextServerIndex:呼び出される特定のサービスインスタンスのインデックス
自己実装のポーリングアルゴリズム
ポーリングアルゴリズム実装クラス
// 手写负载均衡算法(轮询)
public interface LoadBalance {
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
@Component
public class MyLB implements LoadBalance {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 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);
}
}
プロデューサーモジュール(コードの一部)、コンシューマーがrestTemplateを介して呼び出す
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping(value = "/payment/lb")
public String getPaymentLB() {
return serverPort;
}
}
コンシューマーモジュール(部分コード)
/**
* 消费者进行服务调用
*/
@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 LoadBalance loadBalance;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping(value = "/consumer/payment/lb")
public String getPaymentLB() {
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances.size() <= 0) {
return null;
}
// 在CLOUD-PAYMENT-SERVICE的服务集合中(payment8001,8002)进行选择
ServiceInstance serviceInstance = loadBalance.instances(instances);
URI uri = serviceInstance.getUri();
System.out.println(uri);
return restTemplate.getForObject(uri + "/payment/lb", String.class);
}
}
試験結果