当前位置:   article > 正文

基于springcloud服务灰度发布(一)_springcloud 灰度发布

springcloud 灰度发布

1 解决的问题

为了解决越来越频繁的服务更新上线,版本回退,快速迭代;服务灰度发很好地解决该问题;
该系列文章主要介绍基于springcloud实现服务灰度发布,下图大致灰度发布系统各个组成部分及路由过程;
在这里插入图片描述

2 灰度发布实现构成

2.1 注册中心(eureka)

不解释

2.2 网关(cloudegateway)

处理请求灰度打标:根据请求信息,如ip,用户id等信息,如果该请求符合灰度策略的用户,那么给该请求添加一个标识为灰度用户的请求头信息;

2.3 服务实例管理后台

给服务实例打标签,服务灰度策略配置;
给服务打标是怎么样实现? 据于eureka服务实及eureka客户端实现,灰度的服务标签信息主要保存于服务实例的metadata里;通过eureka的/eureka/apps/appId/instanceId/metadata?接口设置;然后eureka客户端通过定时拉取服务实例信息,可得到服务实例里的metadata信息;

2.4 负载均衡器(ribbon)

据网关处理请求头标签结果,改写路由规则;
ribbon据请求头标签信息,如何寻找对应服务?由上面可知,eureka 客户端在拉取服务信息列表时,可得服务实例里的metadata里的标签,根据该标签信息,ribbon可判断那个服务实例是正常实例,那些实例是灰度例实;由此再根据请求头灰度标签信息决定路由到那个服务实例

3 ribbon路由规则改写

3.1 修改路由规则

通过分析ribbon实例源码,发现ribbon为每个服务都会创建相应的负载均衡器及负载策略,而这些信息都在RibbonClientConfiguration去被始化,那么改写该配置类则可以修改其负载策略了;下面为改写负载策略的代码
RibbonClientGrayConfig

public class RibbonClientGrayConfig extends RibbonClientConfiguration {
    //具体某个服务名称
    @Value("${ribbon.client.name}")
    private String name = "client";
    //当前应用名称
    @Value("${spring.application.name}")
    private  String appName;

    @Autowired
    private PropertiesFactory propertiesFactory;

    @Bean
    @Primary
    @ConditionalOnMissingBean
    @Override
    public IRule ribbonRule(IClientConfig config) {
        if (this.propertiesFactory.isSet(IRule.class, name)) {
            return this.propertiesFactory.get(IRule.class, config, name);
        }
        //GrayRule自定路由策略,取代原来的策略
        GrayRule rule = new GrayRule(appName,name);
        rule.setEurekaUrls(eurekaUrls);
        rule.initWithNiwsConfig(config);
        return rule;
    }

    //注册一个feign拦截器,处理通过feign远程调用灰度标签传递
    @Bean
    GrayFeignInterceptor grayFeiginInterceptor() {
        return new GrayFeignInterceptor();
    }
}
  • 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

GrayRule

public class GrayRule extends PredicateBasedRule {
    final static Logger logger = LoggerFactory.getLogger(GrayRule.class);
    private AbstractServerPredicate predicate = new GrayPredicate();
    private RoundRobinRule roundRobinRule;
    private String appName;
    private String clientName;
    private String eurekaUrls;
    public void setEurekaUrls(String eurekaUrls) {
        this.eurekaUrls = eurekaUrls;
    }
    public GrayRule() {
    }
    public GrayRule(String appName, String clientName) {
        this.appName = appName;
        this.clientName = clientName;
    }
    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {
        super.initWithNiwsConfig(clientConfig);
        roundRobinRule = new RoundRobinRule();
    }
    @Override
    public void setLoadBalancer(ILoadBalancer lb) {
        super.setLoadBalancer(lb);
        roundRobinRule.setLoadBalancer(lb);
    }
    @Override
    public AbstractServerPredicate getPredicate() {
        return predicate;
    }
    @Override
    public Server choose(Object key) {
        boolean gray = GrayUtils.isGray();
        String routeStatus = gray ? "灰度服务" : "正常服务";
        logger.debug("[{}]将路由到[{}]的{}", appName, clientName, routeStatus);
        Server server = super.choose(gray ? ServerStatus.GRAY : ServerStatus.NORMAL);
        if (gray && server == null) {
            logger.debug("[{}]没有灰度服务实例,回退路由到正常服务", clientName);
            server = super.choose(ServerStatus.NORMAL);
        }
        if (server == null) {
            logger.error("[{}]没有{}实例,请检查服务环境当前注册中心:{}", clientName, routeStatus, eurekaUrls);
        } else {
            logger.debug("当前选择的服务[{}]:{}", clientName, server.getHostPort());
            GrayUtils.setTestServer(server);
        }
        return server;
    }
}
  • 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

灰度服务判断处理

public class GrayPredicate extends AbstractServerPredicate {

    @Override
    public boolean apply(PredicateKey input) {
        Server server = input.getServer();
        ServerInstanceStatus routTo = (ServerInstanceStatus) input.getLoadBalancerKey();
        if (server instanceof DiscoveryEnabledServer) {
            DiscoveryEnabledServer enabledServer = (DiscoveryEnabledServer) server;
            InstanceInfo instanceInfo = enabledServer.getInstanceInfo();
            //从metadata得到服务是否为灰度服务
            String serverStatus = instanceInfo.getMetadata().get(Constant.INSTANCE_STATUS);
            switch (routTo) {
                case GRAY:
                    return ServerInstanceStatus.GRAY.getValue().equals(serverStatus);
                case NORMAL:
                    if (ServerInstanceStatus.GRAY.getValue().equals(serverStatu
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/878187
推荐阅读
相关标签
  

闽ICP备14008679号