Ribbon自定义负载均衡策略实现不同版本的灰度(金丝雀)发布

Posted Cry丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ribbon自定义负载均衡策略实现不同版本的灰度(金丝雀)发布相关的知识,希望对你有一定的参考价值。

文章目录

前言

灰度发布(又名金丝雀发布)是指在黑与白之间,能够平滑过渡的一种发布方式。在其上可以进行A/B testing,即让一部分用户继续用产品特性A,一部分用户开始用产品特性B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度 —— 百度百科

📒 下面把上面这段表述抽象成程序设计模型:

比如现在有2个服务,user服务和order服务,user服务通过在注册中心拉取order服务的地址来消费order服务,灰度发布其实就是让v1版本的user去消费v1版本的order,让v2版本的user去消费v2版本的order。

Ribbon是一个Netflix公司开发的的负载均衡组件,通过自定义实现它的负载均衡策略,可以实现我们的需求。

1.配置负载均衡策略

Nacos中有实现一个优先访问同一ClusterName的Service的负载均衡策略NacosRule,我们可以参考其源码实现。

先上GrayReleasedRule的代码:

public class GrayReleasedRule extends AbstractLoadBalancerRule 

    private static final Logger LOGGER = LoggerFactory.getLogger(GrayReleasedRule.class);

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public Server choose(Object key) 
        try 
            String version = this.nacosDiscoveryProperties.getMetadata().get("version");
            DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
            String name = loadBalancer.getName();

            NamingService namingService = nacosDiscoveryProperties
                    .namingServiceInstance();
            List<Instance> instances = namingService.selectInstances(name, true);
            if (CollectionUtils.isEmpty(instances)) 
                LOGGER.warn("no instance in service ", name);
                return null;
            

            List<Instance> instancesToChoose = instances;

            if (StringUtils.isNotBlank(version)) 
                List<Instance> sameClusterInstances = instances.stream()
                        .filter(instance -> Objects.equals(version,
                                instance.getMetadata().get("version")))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(sameClusterInstances)) 
                    instancesToChoose = sameClusterInstances;
                
                else 
                    LOGGER.warn(
                            "A version-service scall occurs,name = , version = , instance = ",
                            name, version, instances);
                
            

            Instance instance = ExtendBalancer.getHostByRandomWeight2(instancesToChoose);

            return new NacosServer(instance);
        
        catch (Exception e) 
            LOGGER.warn("GrayReleasedRule error", e);
            return null;
        
    

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) 
    


首先我们需要继承一个AbstractLoadBalancerRule抽象类,它实现了IRule接口,我们需要实现它的choose(Object key)方法,关键部分的代码我把它摘出来:

 if (StringUtils.isNotBlank(version)) 
                List<Instance> sameClusterInstances = instances.stream()
                        .filter(instance -> Objects.equals(version,
                                instance.getMetadata().get("version")))
                        .collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(sameClusterInstances)) 
                    instancesToChoose = sameClusterInstances;
                
                else 
                    LOGGER.warn(
                            "A version-service scall occurs,name = , version = , instance = ",
                            name, version, instances);
                
            

我选用的注册中心是Nacos,整合到SpringCloud使用,所以我在
在yml配置文件上的元数据metadata字段中配上version字段

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8888
        metadata:
          version: v1

首先获取到我们配置的版本号version

String version = this.nacosDiscoveryProperties.getMetadata().get("version");

判断从注册中心获取的version不为空的时候,判断是否和当前服务的版本号相同,相同的话就去访问同一版本号的服务。

总结,只需要建立多套服务实例,配置不同的版本号,选择目标用户群体,让请求分散到不同版本号的入口服务上,就能实现不同版本服务的隔离。

2.指定负载均衡策略

通过SpringBean生成策略返回一个IRule接口类型的实例交给SpringContainer管理,覆盖掉Ribbon的默认生成策略

@Configuration
public class RibbonGrayReleasedConfig 
    public IRule ribbonRule() 
        return new GrayReleasedRule();
    

补充:Ribbon负载均衡策略


1.RandomRule: 随机选择一个Server。
2.RetryRule: 对选定的负载均衡策略机上重试机制,在一个配置时间段内当选择Server不成功,则一直尝试使用subRule的方式选择一个可用的server。
3.RoundRobinRule: 轮询选择, 轮询index,选择index对应位置的Server。
4.AvailabilityFilteringRule: 过滤掉一直连接失败的被标记为circuit tripped的后端Server,并过滤掉那些高并发的后端Server或者使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就是检查status里记录的各个Server的运行状态。
5.BestAvailableRule: 选择一个最小的并发请求的Server,逐个考察Server,如果Server被tripped了,则跳过。
6.WeightedResponseTimeRule: 根据响应时间加权,响应时间越长,权重越小,被选中的可能性越低。
7.ZoneAvoidanceRule: 默认的负载均衡策略,即复合判断Server所在区域的性能和Server的可用性选择Server,在没有区域的环境下,类似于轮询(RandomRule)
8.NacosRule(Nacos的自定义实现): 同集群优先调用

有兴趣的可以自行测试

以上是关于Ribbon自定义负载均衡策略实现不同版本的灰度(金丝雀)发布的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud Alibaba - 11 Ribbon 自定义负载均衡策略(同集群优先权重负载均衡算法)

Springcloud + nacos + gateway 负载均衡(ribbon)

自定义Ribbon负载均衡策略

Spring Cloud Alibaba - 10 Ribbon 自定义负载均衡策略(权重算法)

Ribbon篇四自定义负载均衡策略

微服务Ribbon负载均衡