SpringCloud LoadBalancer灰度策略实现

如何使用 Spring Cloud 2020 中重磅推荐的负载均衡器 Spring Cloud LoadBalancer (下文简称 SCL),如何扩展负载均衡策略? 你将从本文中获取到答案
快速上手 SCL
如果项目中想使用 SCL,则仅需要添加如下 maven 依赖即可

org.springframework.cloud
spring-cloud-starter-loadbalancer

SCL 是构建服务发现的基础上,由于目前 Spring Cloud Alibaba 并未兼容 SCL (具体兼容方案可以参考 pig),当然你可以选择使用Eureka 测试。

若将 RestTemplate 和 客户端负载均衡结合使用,在 bean 定义上增加 @LoadBalanced 注解即可.

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值