其他零散知识点开源框架-SpringCloud系列个人学习

SpringCloud LoadBalancer灰度策略实现

2021-01-15  本文已影响0人  冷冷zz

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

快速上手 SCL

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
    return new RestTemplate();
}

个性化负载均衡策略

SCL 内置的负载均衡策略
@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);
    }
}

自定义负载均衡策略

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

        // 遍历可以实例元数据,若匹配则返回此实例
        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'

优化负载均衡策略注入

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

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

上一篇下一篇

猜你喜欢

热点阅读