SpringCloud LoadBalancer灰度策略實(shí)現(xiàn)
如何使用 Spring Cloud 2020 中重磅推薦的負(fù)載均衡器 Spring Cloud LoadBalancer (下文簡稱 SCL),如何擴(kuò)展負(fù)載均衡策略?你將從本文中獲取到答案
快速上手 SCL
如果項(xiàng)目中想使用 SCL,則僅需要添加如下 maven 依賴即可
?org.springframework.cloud
?spring-cloud-starter-loadbalancer
SCL 是構(gòu)建服務(wù)發(fā)現(xiàn)的基礎(chǔ)上,由于目前 Spring Cloud Alibaba 并未兼容 SCL (具體兼容方案可以參考 pig[1]),當(dāng)然你可以選擇使用Eureka 測試。
若將 RestTemplate 和 客戶端負(fù)載均衡結(jié)合使用,在 bean 定義上增加
@LoadBalanced注解即可.
@Bean
@LoadBalanced
public?RestTemplate?restTemplate()?{
????return?new?RestTemplate();
}
個性化負(fù)載均衡策略

目前版本 (spring cloud 2020) 內(nèi)置輪詢、隨機(jī)的負(fù)載均衡策略,默認(rèn)輪詢策略。?
當(dāng)然可以通過
LoadBalancerClient注解,指定服務(wù)級別的負(fù)載均衡策略
@LoadBalancerClient(value?=?"demo-provider",?configuration?=?RandomLoadbalancerConfig.class)
public?class?RandomLoadbalancerConfig?{
?@Bean
?public?ReactorLoadBalancer?reactorServiceInstanceLoadBalancer(Environment?environment,
???LoadBalancerClientFactory?loadBalancerClientFactory)? {
??String?name?=?environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
??return?new?RandomLoadBalancer(
????loadBalancerClientFactory.getLazyProvider(name,?ServiceInstanceListSupplier.class),?name);
?}
}
自定義負(fù)載均衡策略
通過上文可知,目前 SCL 支持的負(fù)載均衡策略相較于
Ribbon還是較少,需要開發(fā)者自行實(shí)現(xiàn),好在 SCL 提供了便捷的 API 方便擴(kuò)展使用。這里演示自定義一個基于注冊中心元數(shù)據(jù)的灰度負(fù)載均衡策略。定義灰度負(fù)載均衡策略
@Slf4j
public?class?GrayRoundRobinLoadBalancer?extends?RoundRobinLoadBalancer?{
?private?ObjectProvider?serviceInstanceListSupplierProvider;
?private?String?serviceId;
?@Override
?public?Mono>?choose(Request?request)?{
??ServiceInstanceListSupplier?supplier?=?serviceInstanceListSupplierProvider
????.getIfAvailable(NoopServiceInstanceListSupplier::new);
??return?supplier.get(request).next().map(serviceInstances?->?getInstanceResponse(serviceInstances,?request));
?}
?Response?getInstanceResponse(List?instances,?Request?request) ? {
??//?注冊中心無可用實(shí)例?拋出異常
??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í)例元數(shù)據(jù),若匹配則返回此實(shí)例
??for?(ServiceInstance?instance?:?instances)?{
???NacosServiceInstance?nacosInstance?=?(NacosServiceInstance)?instance;
???Map?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();
?}
}
針對客戶端注入灰度負(fù)載均衡策略
@LoadBalancerClient(value?=?"demo-provider",?configuration?=?GrayRoundLoadbalancerConfig.class)
服務(wù)實(shí)例定義版本號

請求攜帶版本號,測試使用
curl?--location?--request?GET?'http://localhost:6060/req?key=b'?\
--header?'VERSION:?b'
優(yōu)化負(fù)載均衡策略注入
如上文所述,所有的個性化負(fù)載策略都需要手動通過 LoadBalancerClient注入非常的不方便。我們可以參考LoadBalancerClients的批量注入邏輯構(gòu)造自己的 BeanRegistrar

public?class?GrayLoadBalancerClientConfigurationRegistrar?implements?ImportBeanDefinitionRegistrar?{
?@Override
?public?void?registerBeanDefinitions(AnnotationMetadata?metadata,?BeanDefinitionRegistry?registry)?{
??Field[]?fields?=?ReflectUtil.getFields(ServiceNameConstants.class);
??//?遍歷服務(wù)名稱,注入支持灰度策略的負(fù)載均衡器
??for?(Field?field?:?fields)?{
???Object?fieldValue?=?ReflectUtil.getFieldValue(ServiceNameConstants.class,?field);
???registerClientConfiguration(registry,?fieldValue,?GrayLoadBalancerClientConfiguration.class);
??}
?}
}
參考資料
兼容Spring Cloud 2020 方案: https://gitee.com/log4j/pig
往期推薦
評論
圖片
表情
