Spring Cloud 服務第一次請求超時的優化

aoho發表於2017-11-19

1. 問題背景

使用Spring Cloud元件構建的服務叢集,在第一次請求時經常會出現timeout的情況,然而第二次就正常了。Spring Cloud版本為Dalston.SR4。

啟動涉及到的相關服務:

  • gateway(zuul閘道器)
  • auth-Service(鑑權服務)
  • user-Service(使用者服務)

測試的端點介面為:http:/login/oauth/token。服務之間的呼叫順序為:gateway->auth-Service->user-Service。閘道器收到客戶端的請求,轉發請求到鑑權服務,鑑權服務對使用者身份的核驗是通過呼叫使用者服,使用者服務給鑑權服務返回身份校驗的結果,鑑權服務將身份授權資訊返回給gateway,gateway將最終的結果response返回給客戶端。
三個服務啟動後,通過zipkin監控呼叫鏈路資訊,可以看到第一次和第二次呼叫情況如下圖所示:

not-eager-1st
not-eager-1st

second
second

通過上面兩次的鏈路監控資訊截圖,可以看到第一次的耗時是第二次的10多倍。遇到某些情況,很可能會出現第一次請求的超時。去官網看了下,主要原因是zuul閘道器和各個呼叫服務之間的Ribbon進行客戶端負載均衡的Client懶載入,導致第一次的請求呼叫包括了建立Ribbon Client的時間。通過啟動日誌資訊就可以發現:

lazy-load
lazy-load

下面分兩部分解決這個問題,一是服務之間呼叫Ribbon的飢餓載入,對應上面的測試為auth-Service呼叫user-Service;二是zuul閘道器的飢餓載入。

2. ribbon的飢餓載入

經過調查發現,造成第一次auth-Service呼叫user-Service耗時長的原因主要是,Ribbon進行客戶端負載均衡的服務例項並不是在服務啟動的時候就初始化好的,而是在呼叫的時候才會去建立相應的服務例項。所以第一次呼叫user-Service耗時不僅僅包含傳送HTTP請求的時間,還包含了建立Ribbon Client的時間,這樣一來如果建立時間速度較慢,同時設定的請求超時又比較短的話,很容易就會出現耗時很長甚至超時的情況。
在官網可以看到如下的配置說明:

Each Ribbon named client has a corresponding child Application Context that Spring Cloud maintains, this application context is lazily loaded up on the first request to the named client. This lazy loading behavior can be changed to instead eagerly load up these child Application contexts at startup by specifying the names of the Ribbon clients.

意為Spring Cloud為每個Ribbon客戶端維護了一個相對的子應用環境的上下文,應用的上下文在第一次請求到指定客戶端的時候懶載入。不過可以通過如下配置進行修改:

ribbon:
  eager-load:
    enabled: true
    clients: client1, client2, client3複製程式碼

按照如上的配置之後,發現鑑權服務啟動時就將user服務的Ribbon客戶端進行了載入。

el
el

3. zuul閘道器的飢餓載入

上面小節解決了auth-Service呼叫user-Service的Ribbon客戶端啟動時飢餓載入。閘道器作為對外請求的入口,zuul內部使用Ribbon呼叫其他服務,Spring Cloud預設在第一次呼叫時懶載入Ribbon客戶端。zuul同樣需要維護一個相對的子應用環境的上下文,所以也需要啟動時飢餓載入。

Zuul internally uses Ribbon for calling the remote url’s and Ribbon clients are by default lazily loaded up by Spring Cloud on first call. This behavior can be changed for Zuul using the following configuration and will result in the child Ribbon related Application contexts being eagerly loaded up at application startup time.

具體配置如下:

zuul:
  ribbon:
    eager-load:
      enabled: true複製程式碼

至此,優化完成,再次重啟服務進行第一次請求,發現情況已經好多了,大家可以自己動手嘗試改進一下。

4. 總結

本文主要介紹了Spring Cloud的服務第一次請求超時的優化方法。首先介紹了問題的背景,並排查了問題造成的原因,主要是Ribbon客戶端的懶載入;然後分別針對zuul閘道器和服務之間呼叫的Ribbon客戶端進行配置,使其啟動時便載入Ribbon客戶端的相關上下文資訊。最後想說的是,http呼叫畢竟還是效能遠低於RPC。。?

訂閱最新訊息,關注公眾號,加入我的星球。

xq
xq


參考

  1. spring-cloud Dalston.SR4
  2. Spring Cloud實戰小貼士:Ribbon的飢餓載入(eager-load)模式

相關文章