如何使用 Spring Cloud 2020 中重磅推薦的負載均衡器 Spring Cloud LoadBalancer (下文簡稱 SCL),如何擴展負載均衡策略? 你將從本文中獲取到答案
快速上手 SCL
- 如果項目中想使用 SCL簸喂,則僅需要添加如下 maven 依賴即可
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
SCL 是構(gòu)建服務發(fā)現(xiàn)的基礎上,由于目前 Spring Cloud Alibaba 并未兼容 SCL (具體兼容方案可以參考 pig)试溯,當然你可以選擇使用Eureka 測試。
若將 RestTemplate 和 客戶端負載均衡結(jié)合使用郊酒,在 bean 定義上增加
@LoadBalanced
注解即可.
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
個性化負載均衡策略
- 目前版本 (spring cloud 2020) 內(nèi)置輪詢遇绞、隨機的負載均衡策略,默認輪詢策略燎窘。
- 當然可以通過
LoadBalancerClient
注解摹闽,指定服務級別的負載均衡策略
@LoadBalancerClient(value = "demo-provider", configuration = RandomLoadbalancerConfig.class)
public class RandomLoadbalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
自定義負載均衡策略
通過上文可知,目前 SCL 支持的負載均衡策略相較于
Ribbon
還是較少褐健,需要開發(fā)者自行實現(xiàn)付鹿,好在 SCL 提供了便捷的 API 方便擴展使用。 這里演示自定義一個基于注冊中心元數(shù)據(jù)的灰度負載均衡策略蚜迅。定義灰度負載均衡策略
@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private String serviceId;
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request));
}
Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {
// 注冊中心無可用實例 拋出異常
if (CollUtil.isEmpty(instances)) {
log.warn("No instance available {}", serviceId);
return new EmptyResponse();
}
DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
RequestData clientRequest = (RequestData) requestContext.getClientRequest();
HttpHeaders headers = clientRequest.getHeaders();
String reqVersion = headers.getFirst(CommonConstants.VERSION);
if (StrUtil.isBlank(reqVersion)) {
return super.choose(request).block();
}
// 遍歷可以實例元數(shù)據(jù)舵匾,若匹配則返回此實例
for (ServiceInstance instance : instances) {
NacosServiceInstance nacosInstance = (NacosServiceInstance) instance;
Map<String, String> metadata = nacosInstance.getMetadata();
String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION);
if (reqVersion.equalsIgnoreCase(targetVersion)) {
log.debug("gray requst match success :{} {}", reqVersion, nacosInstance);
return new DefaultResponse(nacosInstance);
}
}
// 降級策略,使用輪詢策略
return super.choose(request).block();
}
}
- 針對客戶端注入灰度負載均衡策略
@LoadBalancerClient(value = "demo-provider", configuration = GrayRoundLoadbalancerConfig.class)
- 服務實例定義版本號
- 請求攜帶版本號谁不,測試使用
curl --location --request GET 'http://localhost:6060/req?key=b' \
--header 'VERSION: b'
優(yōu)化負載均衡策略注入
- 如上文所述纽匙,所有的個性化負載策略都需要手動通過
LoadBalancerClient
注入非常的不方便。 我們可以參考LoadBalancerClients
的批量注入邏輯構(gòu)造自己的 BeanRegistrar
public class GrayLoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Field[] fields = ReflectUtil.getFields(ServiceNameConstants.class);
// 遍歷服務名稱拍谐,注入支持灰度策略的負載均衡器
for (Field field : fields) {
Object fieldValue = ReflectUtil.getFieldValue(ServiceNameConstants.class, field);
registerClientConfiguration(registry, fieldValue, GrayLoadBalancerClientConfiguration.class);
}
}
}