zuul網關實現灰度發布


本文使用zuul網關實現灰度發布,包括了網關到服務、服務到服務的灰度。項目gitee:https://gitee.com/menbbo/gray-demo.git

服務部署可分為三種方式

1)藍綠發布

  藍綠發布是通過冗余的方式來解決部署問題,生產環境為綠色配置,冗余的服務為藍色配置。在部署服務時,首先在冗余服務器上部署最新代碼,由部分用戶使用,

若使用沒有問題,則通過負載均衡將所有用戶請求轉發到冗余服務器中,即冗余的服務轉變為生產環境服務。優點是無需停機部署,服務回滾方便。缺點耗費服務器資源。

2)滾動發布

  滾動發布指每次只部署一個或多個服務,直到服務部署完成為止。優點:用戶無感知,平滑過渡;相比藍綠發布節省服務器資源。缺點:部署復雜,且時間長;遇到

問題回滾比較復雜。

3)灰度發布

  只升級部分服務,讓少量用戶訪問新部署的服務,其他用戶使用老服務,用戶反饋無誤后,整個集群部署,將用戶遷移到新服務上來。優點:在灰度時即可發現問題及

時處理,保證系統穩定性;如果出現問題,影響范圍小;用戶無感知,過渡平滑。

灰度發布實現步驟:

1)定義規則:哪些用戶可以訪問灰度環境,比如按百分比(10%的用戶可以訪問灰度),或讓固定用戶先體驗灰度環境;

2)利用網關實現路由策略,即網關到服務的路由;

3)服務與服務之間的調用使用ribbon實現灰度規則。

代碼實現

代碼使用zuul網關實現,項目包括了zuul、im、search三個服務,im服務調用search服務,具體實現如下。

1.引入maven依賴,關鍵依賴

  <dependency>
            <groupId>io.jmnarloch</groupId>
            <artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
            <version>2.1.0</version>
 </dependency>        
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
            <version>1.4.6.RELEASE</version>
 </dependency>

2.application.properties配置文件進行配置

server.port=9090

spring.application.name=zuul
#注冊中心
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
eureka.instance.prefer-ip-address=true
eureka.client.registerWithEureka=true 
#zuul網關路由 前綴
zuul.routes.prefix=/zuul
zuul.routes.im.path=/im/**
#im代表自定義服務
zuul.routes.im.service-id=im
#false不會截取  true截取前綴
zuul.routes.im.stripPrefix=true

#http://localhost:9090/zuul/im/index

3.GrayFilter過濾器實現網關到服務的灰度規則

@Component
public class GrayFilter extends ZuulFilter {
    private static final String GRAY = "gray";
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        //是否開啟過濾
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        //實現灰度邏輯
        //前端在請求頭中攜帶灰度標識字段
        //服務注冊時加入metadata數據,代表該服務節點為灰度節點
        //首先從頭部中獲取標識
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String header = request.getHeader("gray_header");
        //將灰度的請求轉發到meataData中forward為1的服務
        if(StringUtils.equals(header,GRAY)){
            RibbonFilterContextHolder.getCurrentContext().add("forward","1");
        }else {
            RibbonFilterContextHolder.getCurrentContext().add("forward","2");
        }
        return null;
    }
}

4.im、search服務啟動時注冊metadata到注冊中心

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.client.enabled=true
#eureka.instance.hostname=localhost
#eureka.instance.instance-id=im
#灰度端口
server.port=8081
#生產端口
#server.port=8082
spring.application.name=im
#灰度發布需要metadata
#灰度為1
eureka.instance.metadata-map.forward=1

 

eureka.client.service-url.defaultZone=http://localhost:8761/eureka
server.port=8089
spring.application.name=search

#灰度為1
eureka.instance.metadata-map.forward=1

5.實現服務到服務的灰度規則

/**
 *  定義服務間灰度調用規則
 */
@Component
public class GrayRule extends AbstractLoadBalancerRule {

    private static final String GRAY = "gray";
    private static final String GRAY_HEADER = "forward";
    private static final String GRAY_VALUE = "1";
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {

    }

    @Override
    public Server choose(Object o) {
        ILoadBalancer loadBalancer = getLoadBalancer();
        return this.choose(loadBalancer);
    }

    private Server choose(ILoadBalancer lb){
        Server server = null;
        if (server==null){
       //獲取請求頭中的參數,具體實現在gitee Map<String, String> stringStringMap = GrayRibbonParamater.get(); String grayParmater = null; if(stringStringMap!=null){ grayParmater = stringStringMap.get("gray_header"); } //獲得可到達的服務 List<Server> reachableServers = lb.getReachableServers(); for (Server reachableServer : reachableServers) { //獲取服務的metadata Map<String, String> metadata = ((DiscoveryEnabledServer) reachableServer).getInstanceInfo().getMetadata(); if(StringUtils.equals(metadata.get(GRAY_HEADER),GRAY_VALUE)&&StringUtils.equals(grayParmater,GRAY)){ return reachableServer; } } } return server; } }

  

  

  

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM