国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Cloud Gateway實現(xiàn)灰度發(fā)布功能

這篇具有很好參考價值的文章主要介紹了Spring Cloud Gateway實現(xiàn)灰度發(fā)布功能。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

灰度發(fā)布又名金絲雀發(fā)布,在微服務(wù)中的表現(xiàn)為同一服務(wù)同時上線不同版本,讓一部分用戶使用新版本來驗證新特性,如果驗證沒有問題,則將所有用戶都遷移到新版本上。

springcloud gateway 如何實現(xiàn)灰度發(fā)布,gateway,java,開發(fā)語言

在微服務(wù)架構(gòu)中,網(wǎng)關(guān)負責(zé)請求的統(tǒng)一入口,主要功能之一是請求路由。而灰度發(fā)布實質(zhì)就是讓指定用戶路由到指定版本的服務(wù)上。所以該功能可以在網(wǎng)關(guān)這一層實現(xiàn)。

今天就分享下Spring Cloud Gateway如何實現(xiàn)灰度發(fā)布。

1 Spring Cloud Gateway的路由邏輯

既然要讓指定用戶路由到指定服務(wù)版本,我們需要先了解Spring Cloud Gateway的路由邏輯。

Spring Cloud Gateway通過Predicate來匹配路由。

  - id: user-route
      uri: lb://user-login
      predicates:
        - Path=/user/**

上述路由規(guī)則表示只要請求URL符合/user/**則都會匹配到user-route這條路由規(guī)則中。(根據(jù)Predicate尋找路由匹配規(guī)則的源碼在RoutePredicateHandlerMapping#lookupRoute方法中)。

那么要實現(xiàn)灰度發(fā)布該怎么做?我們這里可以自己寫一個Predicate,來實現(xiàn)指定用戶匹配到指定的路由規(guī)則當(dāng)中。假設(shè)我們自己寫的Predicate叫HeaderUserNameRoutePredicateFactory(相應(yīng)源碼在文后),相應(yīng)的配置如下:

  - id: user-route-gray
      uri: lb://user-login
      predicates:
        - Path=/user/**
        - HeaderUsername=Jack

上述路由規(guī)則表示請求URL符合/user/**并且請求的HTTP Header中的Username屬性值為Jack則會匹配到user-route-gray這條路由規(guī)則中。

實現(xiàn)了指定用戶匹配到指定規(guī)則只是第一步,下一步要實現(xiàn)的是如何讓指定用戶路由到指定版本的服務(wù)中,想要實現(xiàn)這一點,就需要先了解Spring Cloud Gateway的負載均衡邏輯,也就是Spring Cloud Gateway是如何選取要調(diào)用的服務(wù)的。

2 Spring Cloud Gateway的負載均衡邏輯

負載均衡的邏輯如下:

1、 從注冊中心獲取服務(wù)實例列表(實際實現(xiàn)中服務(wù)實例列表是后臺定時刷新緩存在內(nèi)存中的);

2、根據(jù)負載均衡算法從實例列表中選取服務(wù)。

在Spring Cloud Gateway中,相應(yīng)的代碼在ReactiveLoadBalancerClientFilter#choose方法中。

默認情況下,Spring Cloud Gateway負載均衡策略會從注冊中心所有服務(wù)實例中輪詢選擇一個服務(wù)實例。由此可以看出,默認實現(xiàn)無法滿足我們的需求,因為我們想要特定用戶路由到特定的服務(wù)版本上。

那么該如何解決呢?答案是重寫負載均衡算法,來實現(xiàn)選擇特定版本的服務(wù)實例功能。

3 版本號如何指定

灰度發(fā)布的目的是實現(xiàn)指定用戶訪問指定版本,用戶信息可以在HTTP Header中帶過來,那么版本號如何指定?

這里有兩種方案。

第一種方案也是通過請求的HTTP Header帶過來,缺點是需要客戶端修改;

第二種方案是在網(wǎng)關(guān)層修改請求,動態(tài)為請求加上版本號信息,此方案較好,對客戶端透明。

4 灰度發(fā)布的實現(xiàn)

看到這里,整個灰度發(fā)布的實現(xiàn)思路應(yīng)該比較清晰了。

1、首先編寫自己的Predicate,實現(xiàn)指定用戶匹配到指定的路由規(guī)則中;

2、動態(tài)修改請求,添加版本號信息,版本號信息可以放在HTTP Header中(此處可以通過原生AddRequestHeaderGatewayFilterFactory來實現(xiàn),無需自己寫代碼);

3、重寫負載均衡算法,根據(jù)版本號信息從注冊中心的服務(wù)實例上選擇相應(yīng)的服務(wù)版本進行請求的轉(zhuǎn)發(fā)。

思路如上,下面附上關(guān)鍵代碼:

自定義HeaderUsernameRoutePredicateFactory源碼如下:

@Component
public class HeaderUsernameRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderUsernameRoutePredicateFactory.Config> {

    public static final String USERNAME = "Username";

    public HeaderUsernameRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST;
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("username");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        List<String> usernames = config.getUsername();
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                String username = serverWebExchange.getRequest().getHeaders().getFirst(USERNAME);
                if (!StringUtils.isEmpty(username)) {
                    return usernames.contains(username);
                }
                return false;
            }

            @Override
            public String toString() {
                return String.format("Header: Username=%s", config.getUsername());
            }
        };
    }

    @NoArgsConstructor
    @Getter
    @Setter
    @ToString
    public static class Config {
        private List<String> username;
    }
}

自定義負載均衡算法GrayRoundRobinLoadBalancer如下:

@Slf4j
public class GrayRoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {

	private static final position = new AtomicInteger(new Random().nextInt(1000));
    private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private final String serviceId;
    private final AtomicInteger position;

    public GrayRoundRobinLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        HttpHeaders headers = (HttpHeaders) request.getContext();
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map(list -> getInstanceResponse(list, headers));
    }

    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, HttpHeaders headers) {
        List<ServiceInstance> serviceInstances = instances.stream()
                .filter(instance -> {
                    //根據(jù)請求頭中的版本號信息,選取注冊中心中的相應(yīng)服務(wù)實例
                    String version = headers.getFirst("Version");
                    if (version != null) {
                        return version.equals(instance.getMetadata().get("version"));
                    } else {
                        return true;
                    }
                }).collect(Collectors.toList());
        if (serviceInstances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
        int pos = Math.abs(this.position.incrementAndGet());
        ServiceInstance instance = serviceInstances.get(pos % serviceInstances.size());
        return new DefaultResponse(instance);
    }
}

自定義GrayReactiveLoadBalancerClientFilter,調(diào)用自定義的負責(zé)均衡算法:

@Slf4j
@Component
public class GrayReactiveLoadBalancerClientFilter implements GlobalFilter, Ordered {

    private static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10150;

    private final LoadBalancerClientFactory clientFactory;

    public GrayReactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory) {
        this.clientFactory = clientFactory;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        URI url = (URI) exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        String schemePrefix = (String) exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_SCHEME_PREFIX_ATTR);
        if (url != null && ("grayLb".equals(url.getScheme()) || "grayLb".equals(schemePrefix))) {
            ServerWebExchangeUtils.addOriginalRequestUrl(exchange, url);
            if (log.isTraceEnabled()) {
                log.trace(ReactiveLoadBalancerClientFilter.class.getSimpleName() + " url before: " + url);
            }
            return this.choose(exchange).doOnNext((response) -> {
                if (!response.hasServer()) {
                    throw NotFoundException.create(true, "Unable to find instance for " + url.getHost());
                } else {
                    URI uri = exchange.getRequest().getURI();
                    String overrideScheme = null;
                    if (schemePrefix != null) {
                        overrideScheme = url.getScheme();
                    }

                    DelegatingServiceInstance serviceInstance = new DelegatingServiceInstance((ServiceInstance) response.getServer(), overrideScheme);
                    URI requestUrl = this.reconstructURI(serviceInstance, uri);
                    if (log.isTraceEnabled()) {
                        log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);
                    }

                    exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, requestUrl);
                }
            }).then(chain.filter(exchange));
        } else {
            return chain.filter(exchange);
        }
    }

    private Mono<Response<ServiceInstance>> choose(ServerWebExchange exchange) {
        URI uri = (URI) exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        GrayRoundRobinLoadBalancer loadBalancer = new GrayRoundRobinLoadBalancer(clientFactory.getLazyProvider(uri.getHost(), ServiceInstanceListSupplier.class), uri.getHost());
        return loadBalancer.choose(this.createRequest(exchange));
    }

    private Request createRequest(ServerWebExchange exchange) {
        HttpHeaders headers = exchange.getRequest().getHeaders();
        return new DefaultRequest<>(headers);
    }

    protected URI reconstructURI(ServiceInstance serviceInstance, URI original) {
        return LoadBalancerUriTools.reconstructURI(serviceInstance, original);
    }

    @Override
    public int getOrder() {
        return LOAD_BALANCER_CLIENT_FILTER_ORDER;
    }
}

最后的路由規(guī)則配置如下,表示用戶Jack走V2版本,其他用戶走V1版本:

 - id: user-route-gray
      uri: grayLb://user-login
      predicates:
        - Path=/user/**
        - HeaderUsername=Jack
      filters:
        - AddRequestHeader=Version,v2
 - id: user-route
      uri: grayLb://user-login
      predicates:
        - Path=/user/**
      filters:
        - AddRequestHeader=Version,v1

寫在最后

微服務(wù)中的灰度發(fā)布功能如上所述,相比實現(xiàn),思路是大家更需要關(guān)注的地方。思路清晰了,即使換個網(wǎng)關(guān)實現(xiàn),換個注冊中心實現(xiàn),都是一樣的。

灰度發(fā)布實質(zhì)是讓指定用戶訪問指定版本的服務(wù)。

所以首先需要指定用戶匹配到指定的路由規(guī)則。

其次,服務(wù)的版本號信息可以通過HTTP請求頭字段來指定。

最后,負載均衡算法需要能夠根據(jù)版本號信息來做服務(wù)實例的選擇。

轉(zhuǎn)自:公眾號-WU雙

鏈接:https://blog.csdn.net/sslulu520/article/details/118528193文章來源地址http://www.zghlxwxcb.cn/news/detail-832905.html

到了這里,關(guān)于Spring Cloud Gateway實現(xiàn)灰度發(fā)布功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【SpringCloud】11、Spring Cloud Gateway使用Sentinel實現(xiàn)服務(wù)限流

    1、關(guān)于 Sentinel Sentinel 是阿里巴巴開源的一個流量防衛(wèi)防護組件,可以為微服務(wù)架構(gòu)提供強大的流量防衛(wèi)能力,包括流量控制、熔斷降級等功能。Spring Cloud Gateway 與 Sentinel 結(jié)合,可以實現(xiàn)強大的限流功能。 Sentinel 具有以下特性: 豐富的應(yīng)用場景:Sentinel 承接了阿里巴巴近

    2024年02月01日
    瀏覽(23)
  • Spring Cloud Gateway 網(wǎng)關(guān)實現(xiàn)白名單功能

    1 摘要 對于微服務(wù)后臺而言,網(wǎng)關(guān)層作為所有網(wǎng)絡(luò)請求的入口。一般基于安全考慮,會在網(wǎng)關(guān)層做權(quán)限認證,但是對于一些例如登錄、注冊等接口以及一些資源數(shù)據(jù),這些是不需要有認證信息,因此需要在網(wǎng)關(guān)層設(shè)計一個白名單的功能。本文將基于 Spring Cloud Gateway 2.X 實現(xiàn)白

    2023年04月08日
    瀏覽(29)
  • springcloud+nacos實現(xiàn)灰度發(fā)布

    灰度發(fā)布實體 灰度發(fā)布上下文信息 灰度過濾器設(shè)置灰度上下文信息 灰度路由規(guī)則 gateway網(wǎng)關(guān)需要引入的pom 常量 服務(wù)路由規(guī)則 需要傳遞灰度版本號,所以需要把灰度版本請求參數(shù)傳遞下去,以及解決Hystrix的線程切換導(dǎo)致參數(shù)無法傳遞下的問題 使用TransmittableThreadLocal可以跨線

    2024年02月12日
    瀏覽(21)
  • 【springcloud 微服務(wù)】Spring Cloud 微服務(wù)網(wǎng)關(guān)Gateway使用詳解

    目錄 一、微服務(wù)網(wǎng)關(guān)簡介 1.1 網(wǎng)關(guān)的作用 1.2 常用網(wǎng)關(guān) 1.2.1 傳統(tǒng)網(wǎng)關(guān) 1.2.2?云原生網(wǎng)關(guān)

    2023年04月16日
    瀏覽(31)
  • Java之SpringCloud Alibaba【七】【Spring Cloud微服務(wù)網(wǎng)關(guān)Gateway組件】

    Java之SpringCloud Alibaba【七】【Spring Cloud微服務(wù)網(wǎng)關(guān)Gateway組件】

    Java之SpringCloud Alibaba【一】【Nacos一篇文章精通系列】 跳轉(zhuǎn) Java之SpringCloud Alibaba【二】【微服務(wù)調(diào)用組件Feign】 跳轉(zhuǎn) Java之SpringCloud Alibaba【三】【微服務(wù)Nacos-config配置中心】 跳轉(zhuǎn) Java之SpringCloud Alibaba【四】【微服務(wù) Sentinel服務(wù)熔斷】 跳轉(zhuǎn) Java之SpringCloud Alibaba【五】【微服務(wù)

    2024年02月06日
    瀏覽(34)
  • SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān),Route路由,Predicate 謂詞/斷言,F(xiàn)ilter 過濾器(十三)

    SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān),Route路由,Predicate 謂詞/斷言,F(xiàn)ilter 過濾器(十三)

    閱讀本文前可先參考 ??????SpringCloud - Spring Cloud根/父項目,開發(fā)準(zhǔn)備(二)_MinggeQingchun的博客-CSDN博客 SpringCloud - Spring Cloud 之 Gateway網(wǎng)關(guān)(十三)_MinggeQingchun的博客-CSDN博客 Web 有三大組件(監(jiān)聽器 過濾器 servlet),Spring Cloud GateWay 最主要的功能就是路由轉(zhuǎn)發(fā),而在定義

    2024年02月14日
    瀏覽(29)
  • Spring Cloud Gateway集成聚合型Spring Boot API發(fā)布組件knife4j,增強Swagger

    Spring Cloud Gateway集成聚合型Spring Boot API發(fā)布組件knife4j,增強Swagger

    大家都知道,在前后端分離開發(fā)的時代,前后端接口對接是一項必不可少的工作。 可是, 作 為后端開發(fā),怎么和前端更好的配合,才能讓自己不心累、腦累 ,直接扔給前端一個后端開放api接口文檔或者頁面,讓前端不用看著難受,也不用前端老問你,來愉快的合作呢? 原

    2024年04月22日
    瀏覽(22)
  • SpringCloud全鏈路灰度發(fā)布

    SpringCloud全鏈路灰度發(fā)布

    日升時奮斗,日落時自省? 目錄 1、實現(xiàn)框架 2、負載均衡模塊 3、封裝負載均衡器 4、網(wǎng)關(guān)模塊 5、服務(wù)模塊 5.1、注冊為灰度服務(wù)實例 5.2、設(shè)置負載均衡器 5.3、傳遞灰度標(biāo)簽 Spring Cloud全鏈路灰色發(fā)布實現(xiàn)構(gòu)架: 灰度發(fā)布的具體實現(xiàn)?: 前端程序在灰度測試用戶Header頭中打上

    2024年01月21日
    瀏覽(27)
  • Spring Cloud Gateway 實現(xiàn)原理

    Spring Cloud Gateway是Spring Cloud生態(tài)系統(tǒng)中的一個組件,用于構(gòu)建基于Spring Boot的微服務(wù)架構(gòu)中的網(wǎng)關(guān)服務(wù)。它的主要目的是提供一種靈活的方式來路由、過濾和轉(zhuǎn)換HTTP請求,從而允許您構(gòu)建強大、高性能的微服務(wù)應(yīng)用程序。 以下是Spring Cloud Gateway的一些核心原理和功能: 路由(

    2024年02月10日
    瀏覽(26)
  • Spring Cloud GateWay實現(xiàn)熔斷降級

    當(dāng)分布式系統(tǒng)中的網(wǎng)關(guān)接收到大量請求并向后端遠程系統(tǒng)或服務(wù)發(fā)起調(diào)用時,后端服務(wù)可能會產(chǎn)生調(diào)用失敗(如超時或異常)。這時,如果讓請求繼續(xù)堆積在網(wǎng)關(guān)上,可能會導(dǎo)致整個系統(tǒng)的癱瘓。因此,需要快速失敗并返回請求,這就是所謂的熔斷。 降級是指在系統(tǒng)資源不足

    2024年02月02日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包