千家信息网

Spring Cloud Gateway扩展有哪些特点

发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,这篇文章主要讲解了"Spring Cloud Gateway扩展有哪些特点",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Cloud Ga
千家信息网最后更新 2025年01月25日Spring Cloud Gateway扩展有哪些特点

这篇文章主要讲解了"Spring Cloud Gateway扩展有哪些特点",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Cloud Gateway扩展有哪些特点"吧!

灰度发布

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

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

实现方案

nginx + lua (openresty)

Netflix Zuul

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

@Slf4jpublic class MetadataCanaryRuleHandler extends ZoneAvoidanceRule {    @Override    public AbstractServerPredicate getPredicate() {        return new AbstractServerPredicate() {            @Override            public boolean apply(PredicateKey predicateKey) {                String targetVersion = RibbonVersionHolder.getContext();                RibbonVersionHolder.clearContext();                if (StrUtil.isBlank(targetVersion)) {                    log.debug("客户端未配置目标版本直接路由");                    return true;                }                DiscoveryEnabledServer server = (DiscoveryEnabledServer) predicateKey.getServer();                final Map metadata = server.getInstanceInfo().getMetadata();                if (StrUtil.isBlank(metadata.get(SecurityConstants.VERSION))) {                    log.debug("当前微服务{} 未配置版本直接路由");                    return true;                }                if (metadata.get(SecurityConstants.VERSION).equals(targetVersion)) {                    return true;                } else {                    log.debug("当前微服务{} 版本为{},目标版本{} 匹配失败", server.getInstanceInfo().getAppName()                            , metadata.get(SecurityConstants.VERSION), targetVersion);                    return false;                }            }        };    }}

维护请求中的版本号

public class RibbonVersionHolder {    private static final ThreadLocal context = new TransmittableThreadLocal<>();    public static String getContext() {        return context.get();    }    public static void setContext(String value) {        context.set(value);    }    public static void clearContext() {        context.remove();    }}

Spring Cloud Gateway 中实现

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

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

public class LoadBalancerClientFilter implements GlobalFilter, Ordered {        @Override        public int getOrder() {                return LOAD_BALANCER_CLIENT_FILTER_ORDER;        }        @Override        @SuppressWarnings("Duplicates")        public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {                return chain.filter(exchange);        }        protected ServiceInstance choose(ServerWebExchange exchange) {                return loadBalancer.choose(                                ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost());        }}

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

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

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

public abstract class AbstractDiscoveryEnabledPredicate extends AbstractServerPredicate {        /**         * {@inheritDoc}         */        @Override        public boolean apply(@Nullable PredicateKey input) {                return input != null                                && input.getServer() instanceof NacosServer                                && apply((NacosServer) input.getServer(), (HttpHeaders) input.getLoadBalancerKey());        }}

最后根据版本来计算

    public class GrayMetadataAwarePredicate extends AbstractDiscoveryEnabledPredicate {        @Override        protected boolean apply(NacosServer server, HttpHeaders headers) {                PigxRibbonRuleProperties ribbonProperties = SpringContextHolder.getBean(PigxRibbonRuleProperties.class);                if (!ribbonProperties.isGrayEnabled()) {                        log.debug("gray closed,GrayMetadataAwarePredicate return true");                        return true;                }                final Map metadata = server.getMetadata();                String version = metadata.get(CommonConstants.VERSION);                // 判断Nacos服务是否有版本标签                if (StrUtil.isBlank(version)) {                        log.debug("nacos server tag is blank ,GrayMetadataAwarePredicate return true");                        return true;                }                // 判断请求中是否有版本                String target = headers.getFirst(CommonConstants.VERSION);                if (StrUtil.isBlank(target)) {                        log.debug("request headers version is blank,GrayMetadataAwarePredicate return true");                        return true;                }                log.debug("请求版本:{} ,当前服务版本:{}", target, version);                return target.equals(version);        }}

整合nacos

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

感谢各位的阅读,以上就是"Spring Cloud Gateway扩展有哪些特点"的内容了,经过本文的学习后,相信大家对Spring Cloud Gateway扩展有哪些特点这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0