天天看點

網關 Spring Cloud Zuul 給Zuul路由加上自動重試

文章目錄

    • 概要
    • 依賴導入
    • 配置檔案
    • 隔離機制
    • 重試機制

概要

當Netflix Zuul用作将傳入請求轉發到後端服務的網關時,總是有一個請求可能無法後端服務的機會。

當請求失敗時,您可能希望自動重試該請求。為此,在使用Sping Cloud Netflix時,您需要在應用程式的類路徑中包括Spring Retry。當出現Spring Retry時,負載平衡的Zuul會自動重試任何失敗的請求(如下示例配置,如果後端服務關閉,Zuul将重試2次)。

網關 Spring Cloud Zuul 給Zuul路由加上自動重試
  • Zuul使用的預設HTTP用戶端現在由Apache HTTP用戶端而不是已棄用的Ribbon的RestClient。
  • Netflix Ribbon HTTP用戶端:通過設定啟用ribbon.restclient.enabled=true。該用戶端具有局限性,包括不支援PATCH方法,但還具有内置的重試功能。

對應使用Client源碼:

/**
 * An Apache HTTP client which leverages Spring Retry to retry failed requests.
 *
 * @author Ryan Baxter
 * @author Gang Li
 */
public class RetryableRibbonLoadBalancingHttpClient
		extends RibbonLoadBalancingHttpClient {
           

依賴導入

<dependency>
         <groupId>org.springframework.retry</groupId>
         <artifactId>spring-retry</artifactId>
         <version>1.3.0</version>
      </dependency>
           

配置檔案

配置項:

  • ribbon.MaxAutoRetries:1 - 同一伺服器上的最大重試次數(不包括第一次嘗試)
  • ribbon.MaxAutoRetriesNextServer:1 - 要重試的下一個伺服器的最大數目(不包括第一個伺服器)
  • ribbon.OkToRetryOnAllOperations: true - 是否可以重試此用戶端的所有操作
  • ribbon.ServerListRefreshInterval: 2000 - 重新整理伺服器清單的間隔
roadnet-service:
  ribbon:
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    listOfServers: http://10.7.11.13:9006,http://localhost:8081
    ConnectTimeout: 1000
    ReadTimeout: 3000
    MaxTotalHttpConnections: 500
    MaxConnectionsPerHost: 100
    MaxAutoRetries: 1
    MaxAutoRetriesNextServer: 1
           

隔離機制

在微服務的模式下,應用之間的聯系變得沒那麼強烈,理想中任何一個應用超過負載或是挂掉了,都不應該去影響到其他應用。但是在 Gateway 這個層面,有沒有可能出現一個應用負載過重,導緻将整個 Gateway 都壓垮了,已緻所有應用的流量入口都被切斷?

這當然是有可能的,想象一個每秒會接受很多請求的應用,在正常情況下這些請求可能在 10 毫秒之内就能正常響應,但是如果有一天它出了問題,所有請求都會 Block 到 30 秒逾時才會斷開(例如頻繁 Full GC 無法有效釋放記憶體)。那麼在這個時候,Gateway 中也會有大量的線程在等待請求的響應,最終會吃光所有線程,導緻其他正常應用的請求也受到影響。

在 Zuul 中,每一個後端應用都稱為一個 Route,為了避免一個 Route 搶占了太多資源影響到其他 Route 的情況出現,Zuul 使用 Hystrix 對每一個 Route 都做了隔離和限流。

Hystrix 的隔離政策有兩種,基于線程或是基于信号量。Zuul 預設的是基于線程的隔離機制,這意味着每一個 Route 的請求都會在一個固定大小且獨立的線程池中執行,這樣即使其中一個 Route 出現了問題,也隻會是某一個線程池發生了阻塞,其他 Route 不會受到影響。(在2.27版本中預設是信号量)

一般使用 Hystrix 時,隻有調用量巨大會受到線程開銷影響時才會使用信号量進行隔離政策,對于 Zuul 這種網絡請求的用途使用線程隔離更加穩妥。

重試機制

一般來說,後端應用的健康狀态是不穩定的,應用清單随時會有修改,是以 Gateway 必須有足夠好的容錯機制,能夠減少後端應用變更時造成的影響。

Zuul 的路由主要有 Eureka 和 Ribbon 兩種方式,下面簡單介紹下 Ribbon 支援哪些容錯配置。

重試的場景分為三種:

  • okToRetryOnConnectErrors:隻重試網絡錯誤
  • okToRetryOnAllErrors:重試所有錯誤
  • OkToRetryOnAllOperations:重試所有操作(這裡不太了解,猜測是 GET/POST 等請求都會重試)

重試的次數有兩種:

  • MaxAutoRetries:每個節點的最大重試次數
  • MaxAutoRetriesNextServer:更換節點重試的最大次數

一般來說我們希望隻在網絡連接配接失敗時進行重試、或是對 5XX 的 GET 請求進行重試(不推薦對 POST 請求進行重試,無法保證幂等性會造成資料不一緻)。單台的重試次數可以盡量小一些,重試的節點數盡量多一些,整體效果會更好。

如果有更加複雜的重試場景,例如需要對特定的某些 API、特定的傳回值進行重試,那麼也可以通過實作 RequestSpecificRetryHandler 定制邏輯(不建議直接使用 RetryHandler,因為這個子類可以使用很多已有的功能)。

參考:

  • https://www.jianshu.com/p/e0434a421c03

    加群一起抱團取暖,共同進步

🍎QQ群【837324215】

🍎關注我的公衆号【Java大廠面試官】,一起學習呗🍎🍎🍎

🍎個人vx【lakernote】

網關 Spring Cloud Zuul 給Zuul路由加上自動重試