Chapter Seven《SpringCloud微服務(wù)實戰(zhàn)》

API 網(wǎng)關(guān)服務(wù): Spring Cloud Zuul

Sping Cloud Zuul 是什么?

spring cloud zuul是netflix提供的一個組件,功能類似于nginx,用于反向代理,可以提供動態(tài)路由、監(jiān)控、授權(quán)、安全、調(diào)度等邊緣服務(wù)。
微服務(wù)場景下,每一個微服務(wù)對外暴露了一組細粒度的服務(wù)??蛻舳说恼埱罂赡軙婕暗揭淮姆?wù)調(diào)用,如果將這些微服務(wù)都暴露給客戶端,那么會增加客戶端代碼的復(fù)雜度。
將細粒度的服務(wù)組合起來提供一個粗粒度的服務(wù),所有請求都導(dǎo)入一個統(tǒng)一的入口,那么整個服務(wù)只需要暴露一個api,對外屏蔽了服務(wù)端的實現(xiàn)細節(jié),也減少了客戶端與服務(wù)器的網(wǎng)絡(luò)調(diào)用次數(shù)。這就是api gateway。

image.png

有了api gateway之后,一些與業(yè)務(wù)關(guān)系并不大的通用處理邏輯可以從api gateway中剝離出來,api gateway僅僅負責(zé)服務(wù)的編排與結(jié)果的組裝。

Spring Cloud Netflix的Zuul組件可以做反向代理的功能,通過路由尋址將請求轉(zhuǎn)發(fā)到后端的粗粒度服務(wù)上,并做一些通用的邏輯處理。

為什么需要API Gateway

1、簡化客戶端調(diào)用復(fù)雜度

在微服務(wù)架構(gòu)模式下后端服務(wù)的實例數(shù)一般是動態(tài)的,對于客戶端而言很難發(fā)現(xiàn)動態(tài)改變的服務(wù)實例的訪問地址信息。因此在基于微服務(wù)的項目中為了簡化前端的調(diào)用邏輯,通常會引入API Gateway作為輕量級網(wǎng)關(guān),同時API Gateway中也會實現(xiàn)相關(guān)的認證邏輯從而簡化內(nèi)部服務(wù)之間相互調(diào)用的復(fù)雜度。

image.png

2、數(shù)據(jù)裁剪以及聚合

通常而言不同的客戶端對于顯示時對于數(shù)據(jù)的需求是不一致的,比如手機端或者Web端又或者在低延遲的網(wǎng)絡(luò)環(huán)境或者高延遲的網(wǎng)絡(luò)環(huán)境。

因此為了優(yōu)化客戶端的使用體驗,API Gateway可以對通用性的響應(yīng)數(shù)據(jù)進行裁剪以適應(yīng)不同客戶端的使用需求。同時還可以將多個API調(diào)用邏輯進行聚合,從而減少客戶端的請求數(shù),優(yōu)化客戶端用戶體驗

3、多渠道支持

當然我們還可以針對不同的渠道和客戶端提供不同的API Gateway,對于該模式的使用由另外一個大家熟知的方式叫Backend for front-end, 在Backend for front-end模式當中,我們可以針對不同的客戶端分別創(chuàng)建其BFF

image.png

4、遺留系統(tǒng)的微服務(wù)化改造

對于系統(tǒng)系統(tǒng)而言進行微服務(wù)改造通常是由于原有的系統(tǒng)存在或多或少的問題,比如技術(shù)債務(wù),代碼質(zhì)量,可維護性,可擴展性等等。API Gateway的模式同樣適用于這一類遺留系統(tǒng)的改造,通過微服務(wù)化的改造逐步實現(xiàn)對原有系統(tǒng)中的問題的修復(fù),從而提升對于原有業(yè)務(wù)響應(yīng)力的提升。通過引入抽象層,逐步使用新的實現(xiàn)替換舊的實現(xiàn)。

image.png

簡單使用

1、添加依賴

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

引入spring-cloud-starter-zuul

2、配置文件

spring.application.name=gateway-service-zuul
server.port=8888

3、啟動類

  @SpringBootApplication
  @EnableZuulProxy
  public class GatewayServiceZuulApplication {

    public static void main(String[] args) {
          SpringApplication.run(GatewayServiceZuulApplication.class, args);
    }
  }

啟動類添加@EnableZuulProxy,支持網(wǎng)關(guān)路由。

路由的配置

傳統(tǒng)路由

在上面的配置中使用了zuul.toutes..pathzuul.toutes..url參數(shù)的方式配置單實例的路由,而在微服務(wù)架構(gòu)中,為了服務(wù)的高可用,一般會將一個服務(wù)部署多個。傳統(tǒng)的多實例的路由配置,Zuul提供了以下方法:

通過zuul.toutes.<route>.path與zuul.toutes.<route>.serviceId配置,如下:

zuul.routes.feign-consumer.path=/feign/**
zuul.routes.feign-consumer.serviceId=feign-consumer
robbin.eureka.enable=false
feign-consumer.ribbon.listOfServers=http://localhost:50000/,http://localhost:50001/

該配置實現(xiàn)了對符合/feign/**規(guī)則的請求轉(zhuǎn)發(fā)到http://localhost:50000/,http://localhost:50001/兩個實例地址的路由規(guī)則。這里的serviceId是有程序員手動命名的服務(wù)名稱。robbin.eureka.enable=false設(shè)置Ribbon不根據(jù)服務(wù)發(fā)現(xiàn)機制來獲取配置服務(wù)對應(yīng)的實例清單。

服務(wù)路由

zuul:
routes:
api-a:
path: /api-a/**
serviceId: feign-consumer

該配置實現(xiàn)了對符合/api-a/**規(guī)則的請求路徑轉(zhuǎn)發(fā)到名為feign-consumer的服務(wù)實例上去的路由規(guī)則。api-a是任意的路由名稱。還可以使用一種更加簡潔的方法zuul.routes.=,這里serviceId指定具體的服務(wù)名,path配置匹配的請求表達式。

其他配置

zuul.ignored-services=hello-service:忽略掉一個服務(wù);
zuul.ignored-patterns=/**/feign/**: 忽略/feign接口路由;
zuul.prefix:為路由添加統(tǒng)一前綴;
zuul.add-host-header: true:在請求路由轉(zhuǎn)發(fā)前為請求設(shè)置Host頭信息;
zuul.sensitiveHeaders=:設(shè)置全局參數(shù)為空來覆蓋默認敏感頭信息
zuul.routes.<route>.customSensitiveHeaders=true:對指定路由開啟自定義敏感頭
zuul.routes.<route>.sentiviteHeaders=:將指定路由的敏感頭設(shè)置為空。
zuul.retryable=false:關(guān)閉重試機制
zuul.routes.<route>.retryable=false:指定路由關(guān)閉重試機制
zuul.<SimpleClassName>.<fileterType>.disable=true:禁用指定的過濾器,<SimpleClassName>代表過濾器的類名,<fileterType>代表過濾器的類型。

在Zuul中Hystrix和Ribbon的配置與傳統(tǒng)的Hystrix和Ribbon服務(wù)的配置一樣。

Zuul 的核心

Filter是Zuul的核心,用來實現(xiàn)對外服務(wù)的控制。Filter的生命周期有4個,分別是“PRE”、“ROUTING”、“POST”、“ERROR”,整個生命周期可以用下圖來表示。

image.png

Zuul大部分功能都是通過過濾器來實現(xiàn)的,這些過濾器類型對應(yīng)于請求的典型生命周期。

PRE: 這種過濾器在請求被路由之前調(diào)用。我們可利用這種過濾器實現(xiàn)身份驗證、在集群中選擇請求的微服務(wù)、記錄調(diào)試信息等。

ROUTING:這種過濾器將請求路由到微服務(wù)。這種過濾器用于構(gòu)建發(fā)送給微服務(wù)的請求,并使用Apache HttpClient或Netfilx Ribbon請求微服務(wù)。

POST:這種過濾器在路由到微服務(wù)以后執(zhí)行。這種過濾器可用來為響應(yīng)添加標準的HTTP Header、收集統(tǒng)計信息和指標、將響應(yīng)從微服務(wù)發(fā)送給客戶端等。

ERROR:在其他階段發(fā)生錯誤時執(zhí)行該過濾器。 除了默認的過濾器類型,Zuul還允許我們創(chuàng)建自定義的過濾器類型。例如,我們可以定制一種STATIC類型的過濾器,直接在Zuul中生成響應(yīng),而不將請求轉(zhuǎn)發(fā)到后端的微服務(wù)。

路由熔斷

當我們的后端服務(wù)出現(xiàn)異常的時候,我們不希望將異常拋出給最外層,期望服務(wù)可以自動進行一降級。Zuul給我們提供了這樣的支持。當某個服務(wù)出現(xiàn)異常時,直接返回我們預(yù)設(shè)的信息。

我們通過自定義的fallback方法,并且將其指定給某個route來實現(xiàn)該route訪問出問題的熔斷處理。主要繼承ZuulFallbackProvider接口來實現(xiàn),ZuulFallbackProvider默認有兩個方法,一個用來指明熔斷攔截哪個服務(wù),一個定制返回內(nèi)容。

public interface ZuulFallbackProvider {
     /**
      * The route this fallback will be used for.
      * @return The route the fallback will be used for.
*/
    public String getRoute();

    /**
     * Provides a fallback response.
     * @return The fallback response.
     */
    public ClientHttpResponse fallbackResponse();
 }

路由重試

有時候因為網(wǎng)絡(luò)或者其它原因,服務(wù)可能會暫時的不可用,這個時候我們希望可以再次對服務(wù)進行重試,Zuul也幫我們實現(xiàn)了此功能,需要結(jié)合Spring Retry 一起來實現(xiàn)。 此處略。

Zuul高可用

image.png

性能優(yōu)化參考

在application.yml文件中配置線程數(shù)、緩沖大小

server:
    tomcat:
        max-threads: 128 # 最大worker線程
        min-spare-threads: 64 # 最小worker線程
undertow:
        io-threads: 8 # IO線程數(shù),默認為CPU核心數(shù),最小為2
        worker-threads: 40 # 阻塞任務(wù)線程池,值設(shè)置取決于系統(tǒng)的負載,默認為io-threads * 8
        buffer-size: 512 # 每塊buffer的空間大小
        buffers-per-region: 10 # 每個區(qū)分配的buffer數(shù)量
        direct-buffers: 512 # 是否分配的直接內(nèi)存

在application.yml文件中配置zuul和ribbon

zuul:
    host:
        max-total-connections: 500 # 每個服務(wù)的http客戶端連接池最大連接,默認值是200
        max-per-route-connections: 50 # 每個route可用的最大連接數(shù),默認值是20
ribbon-isolation-strategy: THREAD # 可選:SEMAPHORE THREAD

Less is more.

最后編輯于
?著作權(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)容