软件定制开发供应商【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) {    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

首先我们需要继承一个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);                }            }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

spring:  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8888        metadata:          version: v1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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

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

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

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

2.指定负载均衡策略

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

@Configurationpublic class RibbonGrayReleasedConfig {    public IRule ribbonRule() {        return new GrayReleasedRule();    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

补充:


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的自定义实现): 同集群优先调用

有兴趣的可以自行测试

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发