伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

Spring Cloud Gateway 扩展支持多版本控制及灰度发布

来源:本站原创 浏览:114次 时间:2022-10-13
灰度发布

什么是灰度发布,概念请参考,我们来简单的通过下图来看下,通俗的讲:为了保证服务升级过程的平滑过渡提高客户体验,会一部分用户 一部分用户递进更新,这样生产中会同时出现多个版本的客户端,为了保证多个版本客户端的可用需要对应的多个版本的服务端版本。灰度发布就是通过一定策略保证 多个版本客户端、服务端间能够正确对应。

所谓灰度发布,即某个服务存在多个实例时,并且实例版本间的版本并不一致,通过

实现方案nginx + lua (openresty)

Netflix Zuul

只需要自定义ribbon 的断言即可,核心是通过TTL 获取上下请求header中的版本号

  1. @Slf4j

  2. public class MetadataCanaryRuleHandler extends ZoneAvoidanceRule {


  3.    @Override

  4.    public AbstractServerPredicate getPredicate() {

  5.        return new AbstractServerPredicate() {

  6.            @Override

  7.            public boolean apply(PredicateKey predicateKey) {

  8.                String targetVersion = RibbonVersionHolder.getContext();

  9.                RibbonVersionHolder.clearContext();

  10.                if (StrUtil.isBlank(targetVersion)) {

  11.                    log.debug("客户端未配置目标版本直接路由");

  12.                    return true;

  13.                }


  14.                DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer();

  15.                final Map<String, String> metadata = server.getInstanceInfo().getMetadata();

  16.                if (StrUtil.isBlank(metadata.get(SecurityConstants.VERSION))) {

  17.                    log.debug("当前微服务{} 未配置版本直接路由");

  18.                    return true;

  19.                }


  20.                if (metadata.get(SecurityConstants.VERSION).equals(targetVersion)) {

  21.                    return true;

  22.                } else {

  23.                    log.debug("当前微服务{} 版本为{},目标版本{} 匹配失败", server.getInstanceInfo().getAppName()

  24.                            , metadata.get(SecurityConstants.VERSION), targetVersion);

  25.                    return false;

  26.                }

  27.            }

  28.        };

  29.    }

  30. }

维护请求中的版本号

  1. public class RibbonVersionHolder {

  2.    private static final ThreadLocal<String> context = new TransmittableThreadLocal<>();


  3.    public static String getContext() {

  4.        return context.get();

  5.    }


  6.    public static void setContext(String value) {

  7.        context.set(value);

  8.    }


  9.    public static void clearContext() {

  10.        context.remove();

  11.    }

  12. }

Spring Cloud Gateway 中实现

第一反应,参考zuul 的实现,自定义断言,然后从上下中获取版本信息即可。但由于 spring cloud gateway 是基于webflux 的反应式编程,所以传统的TTL或者 RequestContextHolder 都不能正确的维护上下文请求。

先来看 spring clou的 gateway 默认的lb 策略实现 LoadBalancerClientFilter

  1. public class LoadBalancerClientFilter implements GlobalFilter, Ordered {

  2.    @Override

  3.    public int getOrder() {

  4.        return LOAD_BALANCER_CLIENT_FILTER_ORDER;

  5.    }


  6.    @Override

  7.    @SuppressWarnings("Duplicates")

  8.    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

  9.        return chain.filter(exchange);

  10.    }


  11.    protected ServiceInstance choose(ServerWebExchange exchange) {

  12.        return loadBalancer.choose(

  13.                ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());

  14.    }

  15. }

我们只需要重写 choose 方法,把上下文请求传递到路由断言中即可,如下

@Overrideprotected ServiceInstance choose(ServerWebExchange exchange) {    HttpHeaders headers = exchange.getRequest().getHeaders();    return loadBalancer.choose(((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(), headers);}

然后在路由断言中通过 PredicateKey获取到即可

  1. public abstract class AbstractDiscoveryEnabledPredicate extends AbstractServerPredicate {


  2.    /**

  3.     * {@inheritDoc}

  4.     */

  5.    @Override

  6.    public boolean apply(@Nullable PredicateKey input) {

  7.        return input != null

  8.                && input.getServer() instanceof NacosServer

  9.                && apply((NacosServer) input.getServer(), (HttpHeaders) input.getLoadBalancerKey());

  10.    }

  11. }

最后根据版本来计算

  1.    public class GrayMetadataAwarePredicate extends AbstractDiscoveryEnabledPredicate {


  2.    @Override

  3.    protected boolean apply(NacosServer server, HttpHeaders headers) {

  4.        PigxRibbonRuleProperties ribbonProperties = SpringContextHolder.getBean(PigxRibbonRuleProperties.class);


  5.        if (!ribbonProperties.isGrayEnabled()) {

  6.            log.debug("gray closed,GrayMetadataAwarePredicate return true");

  7.            return true;

  8.        }


  9.        final Map<String, String> metadata = server.getMetadata();

  10.        String version = metadata.get(CommonConstants.VERSION);

  11.        // 判断Nacos服务是否有版本标签

  12.        if (StrUtil.isBlank(version)) {

  13.            log.debug("nacos server tag is blank ,GrayMetadataAwarePredicate return true");

  14.            return true;

  15.        }


  16.        // 判断请求中是否有版本

  17.        String target = headers.getFirst(CommonConstants.VERSION);

  18.        if (StrUtil.isBlank(target)) {

  19.            log.debug("request headers version is blank,GrayMetadataAwarePredicate return true");

  20.            return true;

  21.        }


  22.        log.debug("请求版本:{} ,当前服务版本:{}", target, version);

  23.        return target.equals(version);

  24.    }


  25. }

整合nacos

结合nacos的动态配置可以非常方便的实现灰度

总结
  • 以上源码参考个人项目 基于Spring Cloud、OAuth2.0开发基于Vue前后分离的开发平台

  • QQ: 2270033969 一起来聊聊你们是咋用 spring cloud 的吧。欢迎关注我们获得更多的好玩JavaEE 实践


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net