1. 程式人生 > >Spring Cloud(八)Zuul路由閘道器

Spring Cloud(八)Zuul路由閘道器

文章目錄

1 概述

1.1 什麼是Zuul

Zuul是所有裝置和網站請求Netflix流應用程式後端的前門。作為一個邊緣服務應用程式,Zuul旨在實現動態路由,監控,彈性和安全性。它還可以恰當的將請求路由到多個Amazon彈性叢集中。

1.2 為什麼要建造Zuul

大量不同的Netflix API流量有時會導致迅速而無預警地出現問題。我們需要一個能夠迅速改變行為的系統,以應對這些情況。

1.3 Zuul有哪些功能

Zuul使用一系列不同型別的過濾器,使我們能夠快速靈活地將這些功能應用於我們的邊緣服務。這些過濾器可幫助我們執行以下功能:

  1. Authentication and Security(身份驗證和安全性 ):識別每個資源的認證要求並拒絕不滿足它們的請求。
  2. Insights and Monitoring(洞察和監控 ): 在邊緣跟蹤有意義的資料和統計資料,以便給我們一個準確的生產檢視。
  3. Dynamic Routing(動態路由):根據需要動態地向不同的後端叢集路由請求。
  4. Stress Testing(壓力測試):逐漸向叢集增加流量壓力來評估效能。
  5. Load Shedding(甩負荷):為每種型別的請求分配容量,並刪除超出限制的請求。
  6. Static Response handling(靜態響應處理):直接在邊緣建立一些響應,而不是將它們轉發到內部叢集。
  7. Multiregion Resiliency(多區域彈性):跨越AWS區域路由請求,以使我們ELB的使用多樣化,並使我們的優勢更靠近我們的成員。

1.4 理解

  1. Zuul路由功能負責將外部的請求轉發到具體的微服務例項上,是實現外部訪問統一入口的基礎。而過濾功能負責隊請求的處理過程進行干預,是實現請求校驗、服務聚合等功能的基礎。
  2. Zuul需要和Eureka整合,將Zuul註冊為Eureka服務治理下的應用,同時從Eureka中獲取其它微服務的訊息,即以後對微服務的訪問都通過Zuul跳轉後獲得。
  3. Zuul就像大樓的保安,你可以請他找人(代理),找的人在外面叫什麼名字(路由),是否允許你進入大樓(過濾)。因為保安屬於物業公司,所以保安要在物業公司註冊,所獲得的資訊也來源於物業公司(與Eureka的關係)。

2 Zuul路由功能

2.1 建立zuul服務

  1. 匯入依賴。
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
</dependencies>
  1. 配置檔案。
server:
  port: 9999
spring:
  application:
    name: spring-cloud-zuul-gateway   #為這個服務取名,非常重要!!!!!
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: zuul.com
    prefer-ip-address: true
  1. 修改hosts檔案。
127.0.0.0 zuul.com
  1. 建立主啟動類,並加入@EnableZuulProxy註解。
@SpringBootApplication
@EnableZuulProxy
public class SpringCloudZuulApplication9999 {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudZuulApplication9999.class, args);
    }
}

2.2 測試

  1. 依次啟動uereka、一個provider、zuul服務,可以看到註冊了兩個微服務。
    在這裡插入圖片描述
  2. 通過http://[服務ip]:[服務埠]/[路徑] 訪問,訪問成功。
    在這裡插入圖片描述
  3. 通過http://[閘道器服務ip]:[閘道器服務埠]/[微服務名稱]/[路徑] 訪問,訪問成功。
    在這裡插入圖片描述
    可以理解為,Zuul在微服務裡找到了名為spring-cloud-provider的微服務,然後通過改為服務的訪問路徑訪問服務

2.3 路由訪問對映規則

2.3.1 修改配置檔案

server:
  port: 9999

spring:
  application:
    name: spring-cloud-zuul-gateway   #為這個服務取名,非常重要!!!!!

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: zuul.com
    prefer-ip-address: true
zuul:
  ignored-services: spring-cloud-provider #禁止通過微服務名訪問,可以使用萬用字元*
  prefix: /mysevice #訪問字首,如果沒有該配置,則訪問路徑不能以/zuul/開頭
  routes:
    spring-cloud-provider:  /myzuul/**   #routes引數格式為Map,前者是key 為被代理服務名-spring-cloud-provider,後者是value為代理路徑-/myzuul/** ;可以配置多個服務代理
    #spring-cloud-provider1:  /myzuul1/** 

2.3.2 修改後測試

重行啟動zuul服務,訪問:http://zuul.com:9999/mysevice/myzuul/hello/jack
在這裡插入圖片描述
證明:只能通過http://[閘道器服務ip]:[閘道器服務埠]/[字首][自己設定的路徑]/[路徑] 進行訪問,不加字首或者通過服務名訪問都失敗。

3 自定義zuul過濾器

3.1 編寫程式碼

//使該類成為配置類,注入spring容器
@Configuration
public class MyZuulFilter extends ZuulFilter {

    /**
     * pre:在請求路由之前執行過濾。我們可利用這種過濾器實現身份驗證、在叢集中選擇請求的微服務、記錄除錯資訊等。
     * route:這種過濾器將請求路由到微服務。這種過濾器用於構建傳送給微服務的請求,並使用Apache HttpClient或Netfilx Ribbon請求微服務。
     * post:這種過濾器在路由到微服務以後執行。這種過濾器可用來為響應新增標準的HTTP Header、收集統計資訊和指標、將響應從微服務傳送給客戶端等。
     * error:在其他階段發生錯誤時執行該過濾器。
     * 除了預設的過濾器型別,Zuul還允許我們建立自定義的過濾器型別。例如,我們可以定製一種STATIC型別的過濾器,直接在Zuul中生成響應,而不將請求轉發到後端的微服務。
     * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering,
     * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling.
     * We also support a "static" type for static responses see  StaticResponseFilter.
     * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type)
     *
     * @return A String representing that type
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 必須定義過濾器順序,如果該過濾器的優先順序不是很重要,過濾器順序命令可以相同,過濾器命令不需要是連續的。
     * 命令從0,1,2...優先順序依次降低
     * filterOrder() must also be defined for a filter. Filters may have the same  filterOrder if precedence is not
     * important for a filter. filterOrders do not need to be sequential.
     * @return the int order of a filter
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 返回true run()方法將要執行,false將不執行,可以作為run() 方法執行開關。
     * a "true" return from this method means that the run() method should be invoked
     * @return true if the run() method should be invoked. false will not invoke the run() method
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 可以自己編寫任意的業務邏輯
     * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter
     * @return Some arbitrary artifact may be returned. Current implementation ignores it.
     */
    @Override
    public Object run() {
        System.out.println("shouldFilter() is true");
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String requestURL = request.getRequestURL().toString();
        int index = requestURL.lastIndexOf('/')+1;
        String username = requestURL.substring(index);
        //判定長度小於三為非法使用者名稱
        if (username.length() >2 ) {
            return true;
        }else{
            throw new RuntimeException("非法使用者名稱,請檢查!");
        }
    }
}

Zuul中預設實現了DebugFilter、StaticResponseFilter等過濾器,具體資訊可以看原始碼,可以以以下方式禁用某種過濾器

zuul:
    FormBodyWrapperFilter:
        pre:
            disable: true

3.2 測試

  1. 訪問:http://zuul.com:9999/mysevice/myzuul/hello/jack
    在這裡插入圖片描述
  2. 訪問:http://zuul.com:9999/mysevice/myzuul/hello/ja
    在這裡插入圖片描述

4 整合Feign Hystrix,通過客戶端訪問

4.1 新建consumer hystrix zuul服務(複製consumer hystrix)

改寫feign呼叫介面。

@FeignClient(name= "spring-cloud-zuul-gateway", fallback = HelloRemoteFallback.class)
public interface HelloRemote {
    String zuulUrlPrefix = "/mysevice/myzuul";
    @RequestMapping(value = zuulUrlPrefix+"/hello/{name}")
    String hello(@RequestParam(value = "name") String name);
}

4.2 測試

  1. 依次啟動uereka、provider、zuul、consumer hystrix zuul服務。
  2. 訪問:http://localhost/consumer/hello/jack
    在這裡插入圖片描述
  3. 訪問:http://localhost/consumer/hello/ja
    在這裡插入圖片描述

5 Zuul 服務降級

Zuul 是一個代理服務,如果被代理的服務突然宕機(如停掉provider 8001服務),那麼zuul將會報錯。但是consumer hystrix zuul服務已經有Feign降級服務,所以該服務不會報錯,所有隻有zuul報錯,因此應該配置zuul的降級服務。

5.1 新建MyZuulFallbackProvider類,並加入容器

//注入容器
@Component
public class MyZuulFallbackProvider implements ZuulFallbackProvider {
    /**
     * 必須設定好處理的失敗的服務路由
     * @return
     */
    @Override
    public String getRoute() {
        return "spring-cloud-provider";
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return new ClientHttpResponse() {

            /**
             * 服務呼叫失敗後返回
             * @return
             * @throws IOException
             */
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("被代理服務故障,此結果由Zuul Gateway靜態提供!".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders() ;
                headers.set("Content-Type", "text/html; charset=UTF-8");
                return headers;
            }

            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.BAD_REQUEST;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.BAD_REQUEST.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.BAD_REQUEST.getReasonPhrase();
            }
            @Override
            public void close() {

            }};
    }
}

5.2 測試

  1. 停掉provider 8001服務,訪問:http://localhost/consumer/hello/jack
    在這裡插入圖片描述
  2. 訪問:http://zuul.com:9999/mysevice/myzuul/hello/jack
    在這裡插入圖片描述
    原始碼地址