會員服務優雅上下線實踐

隨着會員業務的快速發展,會員系統架構也不斷演進迭代,拆分出了多個微服務,提升了系統的穩定性和擴展能力。在敏捷的開發模式下,業務迭代更加快速,那麼勢必會經常發佈線上服務,在服務上線的過程中,我們發現接口成功率會出現一定程度的下降,對於敏感業務直接影響了用戶的體驗。爲了解決這個問題,我們對微服務上下線流程進行了優化,本文將詳細介紹方案的設計和實現。

01 問題分析

異常情況分析

業務系統當前使用的是 Spring Boot 和 Spring Cloud 框架,服務發佈流程如下圖所示:

通過梳理服務流程發現,引起服務可用性降低、響應時間突增的原因有以下幾點:

優化方向

基於上面的分析,可以通過以下方式解決相關的問題:

  1. 在上線過程中,當服務把依賴的資源都初始化完成後,纔將實例註冊到註冊中心。

  2. 在下線過程中,服務調用方可以排除正在下線的實例,保證在一定的時間窗口內請求不會打到這個實例上。

02 解決方案

系統以集羣方式提供服務,實例的上下線狀態對業務無感知,由組件封裝實例的狀態轉換,通過優雅上線、優雅下線組合來保證服務的無損發佈。

優雅上線

通過預熱功能實現資源初始化,預熱模塊是可插拔的,可全使用或者僅使用其中一個模塊:

  1. 自定義預熱: 由業務方自行擴展實現預熱邏輯。

  2. 線上請求回放預熱: 配置預熱接口,拉取線上請求對本地服務預熱,當接口調用達到配置的預熱次數後,再將服務註冊到註冊中心。

在原生 Spring Cloud Netflix 基礎上,定製開發了服務註冊組件 GracefulServiceRegistration 並抽象了預熱組件 WarmUp。在 Spring 容器初始化過程中,會掃描所有 WarmUp 實現類並注入到容器中,啓動完成後由 GracefulServiceRegistration 組件調用 WarmUp 接口所有實現類的預熱方法進行服務預熱,預熱完成之後再進行服務註冊。

圖例說明:

優雅下線

優雅下線通過延遲下線和可靠負載功能組合實現,在下線過程中,服務實例需要先去取消註冊並將自己標記爲已下線,後續的接口請求都將獲取到該實例的已下線標記。服務調用方根據下線標記把該實例從可用服務列表中剔除,保證在後續一定時間窗口內的請求都不會再打到這個實例上。具體交互流程見下圖:

上文提到在原生 Spring Cloud Netflix 基礎上,定製開發了 GracefulServiceRegistration、WarmUp 等組件,在解決優雅下線問題時,我們又增加了調用插件 InvokePlugin。當 JVM 監聽到 SIGTERM 信號時,下線鉤子線程開始工作,先執行取消註冊,然後通過 GracefulServiceRegistration 標記當前服務爲下線中狀態,並阻塞當前線程 5s(可配置)來保證當前正在處理的請求能夠成功返回。如果此時收到調用方請求,InvokePlugin 會檢查當前服務狀態是否爲下線中,如果是,直接返回下線標記。最後下線鉤子線程被喚醒,再執行對象銷燬邏輯。

圖例說明:

微服務框架使用 Ribbon 作爲負載均衡策略,默認是輪詢機制,BaseLoadBalancer 中維護了兩個註冊表集合:全量註冊表 allServerList、可用註冊表 upServerList,但是原生只使用了全量註冊表,通過循環判斷獲取可用實例,這種方式可能會獲取到不可用的實例,所以我們對邏輯進行了優化,新增一個路由規則,使用可用註冊表保存可用服務實例,並增加任務剔除標記已下線的實例。

負載策略實現方式爲,服務調用方接收到實例的下線標記時,將該實例加入失活隊列,獨立的任務線程處理失活隊列,並維護可用註冊表,且失活隊列的另一個任務是在同步註冊中心最新註冊表的時候,不要把已排除的實例恢復到可用註冊表中。通過重試 + 排除下線實例的方式,使業務得到更高的可用性。具體設計如下:

03 成果與總結

對接優雅上下線功能的服務在上線過程中,服務成功率可以提升到 99.99% 以上,有效解決了服務上線成功率的問題。對比數據見下圖示例:

無優雅上下線(並行 1 臺滾動上線)

開啓優雅上下線(並行 1 臺滾動上線)

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/rxHXhu6NsDWcuutSz13HpA