會員服務優雅上下線實踐
隨着會員業務的快速發展,會員系統架構也不斷演進迭代,拆分出了多個微服務,提升了系統的穩定性和擴展能力。在敏捷的開發模式下,業務迭代更加快速,那麼勢必會經常發佈線上服務,在服務上線的過程中,我們發現接口成功率會出現一定程度的下降,對於敏感業務直接影響了用戶的體驗。爲了解決這個問題,我們對微服務上下線流程進行了優化,本文將詳細介紹方案的設計和實現。
01 問題分析
異常情況分析
業務系統當前使用的是 Spring Boot 和 Spring Cloud 框架,服務發佈流程如下圖所示:
通過梳理服務流程發現,引起服務可用性降低、響應時間突增的原因有以下幾點:
-
過早銷燬對象: 服務正在處理請求,但此時對象被銷燬導致請求報錯。
-
服務未及時下線: 調用方不能及時感知服務已在下線中,仍會發送請求過來,但此時對象可能已經被銷燬導致請求報錯。
-
過早註冊服務: 服務未初始化完成就被註冊到了註冊中心,導致接口響應時間突增甚至超時。
優化方向
基於上面的分析,可以通過以下方式解決相關的問題:
-
在上線過程中,當服務把依賴的資源都初始化完成後,纔將實例註冊到註冊中心。
-
在下線過程中,服務調用方可以排除正在下線的實例,保證在一定的時間窗口內請求不會打到這個實例上。
02 解決方案
系統以集羣方式提供服務,實例的上下線狀態對業務無感知,由組件封裝實例的狀態轉換,通過優雅上線、優雅下線組合來保證服務的無損發佈。
優雅上線
通過預熱功能實現資源初始化,預熱模塊是可插拔的,可全使用或者僅使用其中一個模塊:
-
自定義預熱: 由業務方自行擴展實現預熱邏輯。
-
線上請求回放預熱: 配置預熱接口,拉取線上請求對本地服務預熱,當接口調用達到配置的預熱次數後,再將服務註冊到註冊中心。
- 預熱
在原生 Spring Cloud Netflix 基礎上,定製開發了服務註冊組件 GracefulServiceRegistration 並抽象了預熱組件 WarmUp。在 Spring 容器初始化過程中,會掃描所有 WarmUp 實現類並注入到容器中,啓動完成後由 GracefulServiceRegistration 組件調用 WarmUp 接口所有實現類的預熱方法進行服務預熱,預熱完成之後再進行服務註冊。
圖例說明:
-
VClientAutoConfiguration:服務註冊配置類,負責初始化 GracefulServiceRegistration
-
GracefulServiceRegistration:服務註冊類,觸發服務預熱邏輯執行
-
WarmUp: 預熱組件,由業務方自行擴展實現預熱邏輯。框架默認實現: 延遲 5s(可配置) 再執行服務註冊、線上請求回放預熱
優雅下線
優雅下線通過延遲下線和可靠負載功能組合實現,在下線過程中,服務實例需要先去取消註冊並將自己標記爲已下線,後續的接口請求都將獲取到該實例的已下線標記。服務調用方根據下線標記把該實例從可用服務列表中剔除,保證在後續一定時間窗口內的請求都不會再打到這個實例上。具體交互流程見下圖:
-
延遲下線
上文提到在原生 Spring Cloud Netflix 基礎上,定製開發了 GracefulServiceRegistration、WarmUp 等組件,在解決優雅下線問題時,我們又增加了調用插件 InvokePlugin。當 JVM 監聽到 SIGTERM 信號時,下線鉤子線程開始工作,先執行取消註冊,然後通過 GracefulServiceRegistration 標記當前服務爲下線中狀態,並阻塞當前線程 5s(可配置)來保證當前正在處理的請求能夠成功返回。如果此時收到調用方請求,InvokePlugin 會檢查當前服務狀態是否爲下線中,如果是,直接返回下線標記。最後下線鉤子線程被喚醒,再執行對象銷燬邏輯。
圖例說明:
-
VClientAutoConfiguration:服務註冊配置類,負責初始化 InvokePlugin、GracefulServiceRegistration 等組件
-
GracefulServiceRegistration:服務註冊類,負責延遲銷燬對象、觸發服務預熱邏輯執行
-
InvokePlugin:請求調用插件類,負責執行請求時檢查服務實例狀態是否在下線中,如果在下線中,直接返回下線標記
-
可靠負載
微服務框架使用 Ribbon 作爲負載均衡策略,默認是輪詢機制,BaseLoadBalancer 中維護了兩個註冊表集合:全量註冊表 allServerList、可用註冊表 upServerList,但是原生只使用了全量註冊表,通過循環判斷獲取可用實例,這種方式可能會獲取到不可用的實例,所以我們對邏輯進行了優化,新增一個路由規則,使用可用註冊表保存可用服務實例,並增加任務剔除標記已下線的實例。
負載策略實現方式爲,服務調用方接收到實例的下線標記時,將該實例加入失活隊列,獨立的任務線程處理失活隊列,並維護可用註冊表,且失活隊列的另一個任務是在同步註冊中心最新註冊表的時候,不要把已排除的實例恢復到可用註冊表中。通過重試 + 排除下線實例的方式,使業務得到更高的可用性。具體設計如下:
03 成果與總結
對接優雅上下線功能的服務在上線過程中,服務成功率可以提升到 99.99% 以上,有效解決了服務上線成功率的問題。對比數據見下圖示例:
無優雅上下線(並行 1 臺滾動上線)
開啓優雅上下線(並行 1 臺滾動上線)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/rxHXhu6NsDWcuutSz13HpA