Spring Cloud Zuul(路由網(wǎng)關(guān))

Zuul作為微服務(wù)系統(tǒng)的網(wǎng)關(guān)組件,是從設(shè)備和網(wǎng)站到Netflix流應(yīng)用程序后端的所有請求的前門。作為邊緣服務(wù)應(yīng)用程序,Zuul旨在實現(xiàn)動態(tài)路由,監(jiān)控,彈性和安全性。

官方原話:

Zuul is the front door for all requests from devices and web sites to 
the backend of the Netflix streaming application. 
As an edge service application, Zuul is built to enable dynamic routing, monitoring, 
resiliency and security. It also has the ability to route requests to 
multiple Amazon Auto Scaling Groups as appropriate.

github地址:https://github.com/Netflix/zuul
官方文檔:https://github.com/Netflix/zuul/wiki

不用zuul,讓客戶端直接與各個微服務(wù)通訊,會有以下的問題:

1.客戶端會多次請求不同的微服務(wù),增加了客戶端的復(fù)雜性。
2.存在跨域請求,在一定場景下處理相對復(fù)雜。
3.認證復(fù)雜,每個服務(wù)都需要獨立認證。
4.難以重構(gòu),隨著項目的迭代,可能需要重新劃分微服務(wù)。例如,可能將多個服務(wù)合并成一個或者將一個服務(wù)拆分成多個。如果客戶端直接與微服務(wù)通訊,那么重構(gòu)將會很難實施。
5.某些微服務(wù)可能使用了防火墻/瀏覽器不友好的協(xié)議,直接訪問會有一定困難。

Zuul能干什么?

zuul主要實現(xiàn)的功能就是API Gateway(api網(wǎng)關(guān))的功能

作用:

1.易于監(jiān)控??稍谖⒎?wù)網(wǎng)關(guān)收集監(jiān)控數(shù)據(jù)并將其推送到外部系統(tǒng)進行分析。使用網(wǎng)關(guān)時客戶端只與網(wǎng)關(guān)交互,降低客戶端的調(diào)用邏輯的復(fù)雜度,同時網(wǎng)關(guān)也可以實現(xiàn)認證邏輯簡化內(nèi)部服務(wù)的之間相互調(diào)用的復(fù)雜度。
2.對不同客戶端的支持及數(shù)據(jù)的聚合,如一個網(wǎng)站有web端,手機端,頁面所需的數(shù)據(jù)有同有異,可以將數(shù)據(jù)整合或者裁剪,減少客戶端的請求次數(shù),比如BFF架構(gòu)。
3.可以更好的對項目的微服務(wù)封裝,可將項目的微服務(wù)統(tǒng)一封裝在一個內(nèi)網(wǎng)環(huán)境中,減少了客戶端與各個微服務(wù)之間的交互次數(shù)。只通過網(wǎng)關(guān)提供服務(wù),同時網(wǎng)關(guān)也可以對安全,認證,監(jiān)控,防御單獨強化。
4.易于認證??稍谖⒎?wù)網(wǎng)關(guān)上進行認證。然后再將請求轉(zhuǎn)發(fā)到后端的微服務(wù),而無須在每個微服務(wù)中進行認證。

架構(gòu)圖

image.png

zuul是一個網(wǎng)關(guān)和負載均衡器,在通過ribbon或者feign實現(xiàn)了客戶端負載均衡之后,zuul在服務(wù)端實現(xiàn)負載均衡。zuul支持用任何JVM語言來編寫規(guī)則和過濾條件。

服務(wù)網(wǎng)關(guān)是微服務(wù)架構(gòu)中不可或缺的部分。通過服務(wù)網(wǎng)關(guān)統(tǒng)一向外系統(tǒng)提供REST API的過程中,除了具備服務(wù)路由、均衡負載功能之外,它還具備了權(quán)限控制等功能。
Spring Cloud Netflix中的Zuul就擔任了這樣的一個角色,為微服務(wù)架構(gòu)提供了前門保護的作用,同時將權(quán)限控制這些較重的非業(yè)務(wù)邏輯內(nèi)容遷移到服務(wù)路由層面,使得服務(wù)集群主體能夠具備更高的可復(fù)用性和可測試性。

集成Spring Cloud Zuul

引入Spring Cloud Zuul依賴和相關(guān)依賴,Eureka用來注冊服務(wù)。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

在啟動類加入@EnableZuulProxy 啟用zuul服務(wù),@EnableEurekaClient注冊服務(wù)

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class SpringcloudZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringcloudZuulApplication.class, args);
    }
}

修改yml配置文件

server:
  port: 9100
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9090/eureka
spring:
  application:
    name: springcloud-zuul
zuul:
  routes:
     springcloud-eureka-client:
         path: /eureka-client/**
         serviceId: springcloud-eureka-client
     springcloud-feign-client:
         path: /feign-client/**
         serviceId: springcloud-feign-client

這里主要說下zuul的配置

image.png

可以看出routes下都是map集合
zuul.routes是一個路徑列表,包含多個路由名,可以任意定義,一般用服務(wù)名來命名,每個路由需要path(訪問路徑)和serviceId(服務(wù)名)。

注:以上只是zuul配置中很小的一部分,更多的配置可以參考推薦文章

整體項目結(jié)構(gòu)

Eureka服務(wù)端 端口號是9090
兩個Eureka客戶端 端口號是8081/8082 服務(wù)名springcloud-eureka-client
feign消費者客戶端 端口號是8088 服務(wù)名為springcloud-feign-client
zuul路由網(wǎng)關(guān) 服務(wù)名為springcloud-zuul

啟動服務(wù)進行測試

先啟動服務(wù)端再啟動客戶端,客戶端啟動順序沒要求
訪問http://localhost:9090服務(wù)注冊中心

image.png

在服務(wù)注冊中心可以看到,服務(wù)提供者和消費者都注冊好了

訪問在zuul定義的接口/info,http://localhost:9100/eureka-client/client

image.png

再訪問一次
image.png

zuul默認和Ribbon相結(jié)合實現(xiàn)服務(wù)端負載均衡

下面我們來訪問下springcloud-feign-client的服務(wù),訪問http://localhost:9100/feign-client/info

image.png

也是可以正常訪問的,feign具有客戶端負載均衡,zuul具有服務(wù)端負載均衡,再訪問一次,對應(yīng)的端口肯定是8082
image.png

也許在這其中會報
com.netflix.zuul.exception.ZuulException: Hystrix Readed time out
Caused by: java.lang.RuntimeException: java.net.SocketTimeoutException: Read timed out
Caused by: java.net.SocketTimeoutException: Read timed out

這些根據(jù)報錯信息,應(yīng)該是zuul的調(diào)用等待時間超時

解決方法

yml配置文件中加入

zuul:
  host:
      connect-timeout-millis: 10000
      socket-timeout-millis: 60000

把等待時間設(shè)置得長一點就可以了

Zuul的熔斷功能

Zuul也集成了Hystrix。假如你把springcloud-feign-client服務(wù)關(guān)掉了,它原本的熔斷服務(wù)是不會生效的,因為客戶端不是直接訪問它,所以要在zuul上實現(xiàn)熔斷功能

網(wǎng)上很多博客都是說直接實現(xiàn)ZuulFallbackProvider接口,不過在新版本的springcloud下是會報錯的,找不到這個接口,只適用于Dalston及更低版本

原因:

Edgware.RC1版本中Spring cloud zuul針對于降級進行了升級,升級的內(nèi)容主要是解決上面說到的當降級出現(xiàn)時,怎樣在降級方法中獲取具體的異常信息。
增加了一個 FallbackProvider接口,這個接口替換了ZuulFallbackProvider接口

這個接口有兩個方法

public interface FallbackProvider {
    String getRoute();
    ClientHttpResponse fallbackResponse(String route, Throwable cause);
}

getRoute()主要是表明是為哪個微服務(wù)提供回退,返回*表示為所有微服務(wù)提供回退
Throwable參數(shù)把異常信息也當作參數(shù)傳進來了,在處理熔斷時可以輸出更詳細的信息。
fallbackResponse()為進入熔斷器功能時執(zhí)行的邏輯,返回中斷信息給消費者客戶端

需要實現(xiàn)ClientHttpResponse接口中的方法
getStatusCode()返回響應(yīng)的HTTP狀態(tài)代碼
getRawStatusCode()返回HTTP狀態(tài)代碼
getStatusText()返回響應(yīng)的HTTP狀態(tài)文本
close()關(guān)閉方法,一般不用寫任何代碼
getBody()響應(yīng)體,也就是熔斷的返回內(nèi)容
getHeaders()設(shè)置返回體的頭部
具體可以參考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/client/ClientHttpResponse.html

@Component
public class MyZuulFallbackProvider implements FallbackProvider {
    // 表明是為哪個微服務(wù)提供回退,*表示為所有微服務(wù)提供回退
    @Override
    public String getRoute() {
        return "*";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            //返回響應(yīng)的HTTP狀態(tài)代碼
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }
            // 返回HTTP狀態(tài)代碼
            @Override
            public int getRawStatusCode() throws IOException {
                return this.getStatusCode().value();
            }
            // 返回響應(yīng)的HTTP狀態(tài)文本
            @Override
            public String getStatusText() throws IOException {
                return this.getStatusCode().getReasonPhrase();
            }

            @Override
            public void close() {
            }
            // 響應(yīng)體
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream((route+"服務(wù)不可用!").getBytes());
            }
            // 設(shè)置header
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers=new HttpHeaders();
                MediaType mt=new MediaType("application","json", Charset.forName("UTF-8"));
                headers.setContentType(mt);
                return headers;
            }
        };

    }
}

現(xiàn)在把服務(wù)springcloud-feign-client停掉之后,訪問
http://localhost:9100/feign-client/info

image.png

過濾器是Zuul的核心組件

Zuul大部分功能都是通過過濾器來實現(xiàn)的。Zuul中定義了四種標準過濾器類型,這些過濾器類型對應(yīng)于請求的典型生命周期。
1.PRE:這種過濾器在請求被路由之前調(diào)用。我們可利用這種過濾器實現(xiàn)身份驗證、在集群中選擇請求的微服務(wù)、記錄調(diào)試信息等。
2.ROUTING:這種過濾器將請求路由到微服務(wù),在路由請求時候被調(diào)用。這種過濾器用于構(gòu)建發(fā)送給微服務(wù)的請求,并使用Apache HttpClientNetfilx Ribbon請求微服務(wù)。
3.POST:這種過濾器在路由到微服務(wù)以后執(zhí)行。這種過濾器可用來為響應(yīng)添加標準的
HTTP Header、收集統(tǒng)計信息和指標、將響應(yīng)從微服務(wù)發(fā)送給客戶端等。
4.ERROR:在其他階段發(fā)生錯誤時執(zhí)行該過濾器。

zuul中默認實現(xiàn)的filter

image.png

數(shù)字越大,優(yōu)先級越低
image.png

路由功能在真正運行時,它的路由映射和請求轉(zhuǎn)發(fā)都是由幾個不同的過濾器完成的。其中,路由映射主要通過pre類型的過濾器完成,它將請求路徑與配置的路由規(guī)則進行匹配,以找到需要轉(zhuǎn)發(fā)的目標地址;而請求轉(zhuǎn)發(fā)的部分則是由route類型的過濾器來完成,對pre類型過濾器獲得的路由地址進行轉(zhuǎn)發(fā)。所以說,過濾器可以說是zuul實現(xiàn)api網(wǎng)關(guān)功能最核心的部件,每一個進入zuulhttp請求都會經(jīng)過一系列的過濾器處理鏈得到請求響應(yīng)并返回給客戶端。

總結(jié):

Zuul包含了對請求的路由和過濾兩個功能,其中路由功能負責將外部請求轉(zhuǎn)發(fā)到具體的微服務(wù)實例上,是實現(xiàn)外部訪問統(tǒng)一入口的基礎(chǔ);而過濾器功能則負責對請求的處理過程進行干預(yù),是實現(xiàn)請求校驗,服務(wù)聚合等功能的基礎(chǔ)。
對于zuul過濾器實際使用可以參考
https://www.cnblogs.com/a8457013/p/8352349.html

推薦

關(guān)于zuul的更多配置和使用的可以參考:http://huan1993.iteye.com/blog/2424676

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容