SpringCloud LoadBalancer灰度策略實現

如何使用 Spring Cloud 2020 中重磅推薦的負載均衡器 Spring Cloud LoadBalancer (下文簡稱 SCL),如何擴展負載均衡策略? 你將從本文中獲取到答案react

快速上手 SCLspring

若是項目中想使用 SCL,則僅須要添加以下 maven 依賴便可負載均衡

<dependency>dom

<groupId>org.springframework.cloud</groupId>curl

<artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>maven

SCL 是構建服務發現的基礎上,因爲目前 Spring Cloud Alibaba 並未兼容 SCL ,固然你能夠選擇使用Eureka 測試。ide

若將 RestTemplate 和 客戶端負載均衡結合使用,在 bean 定義上增長 @LoadBalanced 註解便可.oop

@Bean@LoadBalanced測試

public RestTemplate restTemplate() {優化

return new RestTemplate();

}

目前版本 (spring cloud 2020) 內置輪詢、隨機的負載均衡策略,默認輪詢策略。

固然能夠經過 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 仍是較少,須要開發者自行實現,好在 SCL 提供了便捷的 API 方便擴展遠程桌面使用。 這裏演示自定義一個基於註冊中心元數據的灰度負載均衡策略。

定義灰度負載均衡策略

@Slf4jpublic 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();

}

// 遍歷能夠實例元數據,若匹配則返回此實例

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'

優化負載均衡策略注入

如上文所述,全部的個性化負載策略都須要手動經過 LoadBalancerClient 注入很是的不方便。 咱們能夠參考 LoadBalancerClients 的批量注入邏輯構造本身的 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);

相關文章
相關標籤/搜索