SpringCloud LoadBalancer灰度策略实现

如何使用 Spring Cloud 2020 中重磅推荐的负载均衡器 Spring Cloud LoadBalancer (下文简称 SCL),如何扩展负载均衡策略? 你将从本文中获取到答案

快速上手 SCL

  • 如果项目中想使用 SCL,则仅需要添加如下 maven 依赖即可

    <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
  • SCL 是构建服务发现的基础上,由于目前 Spring Cloud Alibaba 并未兼容 SCL (具体兼容方案可以参考 pig),当然你可以选择使用Eureka 测试。

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

    @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); }

个性化负载均衡策略

SCL 内置的负载均衡策略

  • 目前版本 (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 方便扩展使用。 这里演示自定义一个基于注册中心元数据的灰度负载均衡策略。

  • 定义灰度负载均衡策略

    @Slf4j public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {

    1private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider; 2 3private String serviceId; 4 5@Override 6public Mono<Response<ServiceInstance>> choose(Request request) { 7 ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider 8 .getIfAvailable(NoopServiceInstanceListSupplier::new); 9 return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request)); 10} 11 12Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) { 13 14 // 注册中心无可用实例 抛出异常 15 if (CollUtil.isEmpty(instances)) { 16 log.warn("No instance available {}", serviceId); 17 return new EmptyResponse(); 18 } 19 20 DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext(); 21 RequestData clientRequest = (RequestData) requestContext.getClientRequest(); 22 HttpHeaders headers = clientRequest.getHeaders(); 23 24 String reqVersion = headers.getFirst(CommonConstants.VERSION); 25 if (StrUtil.isBlank(reqVersion)) { 26 return super.choose(request).block(); 27 } 28 29 // 遍历可以实例元数据,若匹配则返回此实例 30 for (ServiceInstance instance : instances) { 31 NacosServiceInstance nacosInstance = (NacosServiceInstance) instance; 32 Map<String, String> metadata = nacosInstance.getMetadata(); 33 String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION); 34 if (reqVersion.equalsIgnoreCase(targetVersion)) { 35 log.debug("gray requst match success :{} {}", reqVersion, nacosInstance); 36 return new DefaultResponse(nacosInstance); 37 } 38 } 39 // 降级策略,使用轮询策略 40 return super.choose(request).block(); 41}

    }

  • 针对客户端注入灰度负载均衡策略

    @LoadBalancerClient(value = "demo-provider", configuration = GrayRoundLoadbalancerConfig.class)

  • 服务实例定义版本号

优化负载均衡策略注入

  • 如上文所述,所有的个性化负载策略都需要手动通过 LoadBalancerClient 注入非常的不方便。 我们可以参考 LoadBalancerClients 的批量注入逻辑构造自己的 BeanRegistrar

1public class GrayLoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar { 2 3 @Override 4 public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { 5 Field[] fields = ReflectUtil.getFields(ServiceNameConstants.class); 6 7 // 遍历服务名称,注入支持灰度策略的负载均衡器 8 for (Field field : fields) { 9 Object fieldValue = ReflectUtil.getFieldValue(ServiceNameConstants.class, field); 10 registerClientConfiguration(registry, fieldValue, GrayLoadBalancerClientConfiguration.class); 11 } 12 } 13}

>>> 源码 https://gitee.com/log4j/pig,欢迎署名转载 <<<

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java将前端的json数组字符串转换为列表

记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang