首頁>技術>

網上檢視現有的一些實現gateway灰度釋出的部落格,一般都是使用過濾器、攔截器等,過於複雜,而且不夠靈活,索性自己研究一下gateway,發現可以透過 AbstractLoadBalancerRule 實現,下面是我實現的一套靈活一些的灰度釋出策略。

首先交代下環境:jdk8、SpringBoot 2.3.6.RELEASE、SpringCloud Hoxton.SR9、AlibabaCloud 2.2.3 RELEASE。

gateway的配置檔案如下(可以配置到nacos中):

# 服務灰度釋出配置server:  gray:    config:      # 需要管理釋出的服務server-id,當前為 producer 服務      producer:        # 需要灰度釋出的版本        version: 20210423        # 請求進入灰度服務的機率 0~1,為 0 表示不進入灰度服務,1 則完全灰度        rate: 0 spring:  cloud:    gateway:      routes:        - id: producer_server          uri: lb://producer          predicates:            - Path=/producer/**          filters:            - StripPrefix=0

配置類:

package com.study.gateway.config; import com.alibaba.nacos.common.utils.MapUtils;import lombok.Data;import lombok.Setter;import org.apache.commons.lang3.StringUtils;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component; import java.util.Map; /** * @author zhaochao * @date 2021/4/23 19:44 * @desc 灰度釋出服務配置 */@Component@ConfigurationProperties(prefix = "server.gray")@Setterpublic class ServerGrayProperty {     private Integer maxTryTimes;     private Map<String, Config> config;     public Config getConfig(String name) {        if (MapUtils.isEmpty(config)) {            return null;        }        return config.get(name);    }     @Data    public static class Config {        private String version;        private Double rate;    }     public Integer getMaxTryTimes() {        return maxTryTimes == null || maxTryTimes <= 0 ? 10 : maxTryTimes;    }}

實現灰度釋出的關鍵Configuration:

package com.study.gateway.config; import com.alibaba.cloud.nacos.ribbon.NacosServer;import com.alibaba.nacos.api.naming.pojo.Instance;import com.alibaba.nacos.common.utils.MapUtils;import com.netflix.client.config.IClientConfig;import com.netflix.loadbalancer.BaseLoadBalancer;import com.netflix.loadbalancer.ClientConfigEnabledRoundRobinRule;import com.netflix.loadbalancer.ILoadBalancer;import com.netflix.loadbalancer.Server;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Scope;import org.springframework.util.CollectionUtils; import java.util.List;import java.util.Map;import java.util.Objects;import java.util.concurrent.atomic.LongAdder;import java.util.stream.Collectors; /** * @author zhaochao * @date 2021/4/24 10:26 * @desc 自定義負載均衡策略 服務灰度釋出配置 */@Slf4j@Scope("prototype")@Configurationpublic class ServerGrayRule extends ClientConfigEnabledRoundRobinRule {     private static final LongAdder GRAY_TIMES = new LongAdder();     @Autowired    private ServerGrayProperty serverGrayProperty;     @Override    public void initWithNiwsConfig(IClientConfig clientConfig) {     }     @Override    public Server choose(Object o) {        ILoadBalancer lb = this.getLoadBalancer();        if (!(lb instanceof BaseLoadBalancer)) {            return super.choose(o);        }        Server server = null;        int count = 0;        int max = serverGrayProperty.getMaxTryTimes();        while (server == null && count++ < max) {            if (Thread.interrupted()) {                return null;            }             int allSize = ((BaseLoadBalancer) lb).getServerCount(false);             if (allSize == 0) {                return null;            }             // 灰度獲取服務            server = getServer((BaseLoadBalancer) lb, o);             if (server == null) {                Thread.yield();                continue;            }            if (server.isAlive() && server.isReadyToServe()) {                return server;            }            server = null;            Thread.yield();        }        if (count >= max) {            log.info("No available alive servers after " + max + " tries from load balancer: "                    + lb);        }        return server;    }     private Server getServer(BaseLoadBalancer lb, Object o) {        String name = lb.getName();        ServerGrayProperty.Config config = serverGrayProperty.getConfig(name);        if (Objects.isNull(config)) {            return super.choose(o);        }        // 獲取指定的灰度版本        String targetVersion = config.getVersion();        if (StringUtils.isBlank(targetVersion)) {            return super.choose(o);        }        // 判斷是否需要灰度        boolean needGray = isNeedGray(config.getRate());        // 不需要灰度        if (!needGray) {            return super.choose(o);        }        // 需要灰度        List<Server> servers = lb.getAllServers();        List<Server> grayServers = servers.stream().filter(s -> {            if (!(s instanceof NacosServer)) {                return false;            }            Instance instance = ((NacosServer) s).getInstance();            if (instance == null) {                return false;            }            Map<String, String> metadata = instance.getMetadata();            if (MapUtils.isEmpty(metadata)) {                return false;            }            String version = metadata.get("version");            // 過濾指定的灰度版本            if (!Objects.equals(targetVersion, version)) {                return false;            }            return true;        }).collect(Collectors.toList());        if (CollectionUtils.isEmpty(grayServers)) {            log.error("No gray server to return");            return null;        }        // 輪詢獲取灰度服務索引        int index = getIndex(grayServers.size());        return grayServers.get(index);    }     private int getIndex(int size) {        if (size <= 1) {            return 0;        }        GRAY_TIMES.increment();        return GRAY_TIMES.intValue() % size;    }     /**     * 判斷當前是否需要返回灰度服務     *     * @param rate     * @return     */    private boolean isNeedGray(Double rate) {        // 未配置透過率或小於等於0,不需要灰度 不處理        if (Objects.isNull(rate) || rate <= 0) {            return false;        }        // 完全灰度        if (Objects.equals(rate, 1.0)) {            return true;        }        return Math.random() <= rate;    } }

測試服務producer的配置:

# 服務的元資料spring.cloud.nacos.discovery.metadata.version=2021030V1

在nacos中修改gateway配置中的 version 和 rate 結合 producer服務的元資料,可以動態地實現灰度釋出

nacos

這樣就實現了灰度釋出。

可以繼續進行拓展,結合執行機制及nacos資料儲存結構等實現更為靈活的釋出功能,不僅僅是灰度而已!

5
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Linux系統檔案安全與許可權