
當我們依賴的中間件資源或者是上游服務性能出現嚴重問題時,為了防止用戶看到錯誤頁面或者加載頁面時間過長,我們需要將服務降級靜態頁面。或者將不影響主流程的旁路服務關閉掉,以讓出資源給主要流程。這類操作稱為降級。服務降級方案有三種方式,降低一致性、減少非必要功能、簡化功能,后面我會分別舉例說明。
想要做好降級的前提是,提前壓測得出指標上限,還有提前梳理好系統的性能制約點,比如依賴的服務響應超時時間和基礎負載性能(比如CPU使用率),並納入監控范圍。當前提就緒后,我們就開始編寫異常降級操作手冊,包括托底預案,描述好當發生什么樣的場景時,每一步做什么,它的預期結果是什么,還有是否演練過,只有經過真槍實彈考驗的士兵才是好士兵。最后一點,我們會特別注意的,降級方案是手動生效還是自動生效的,它和止損息息相關。
先來看看手動生效。手動生效意味需要當有人反饋或者監控發現有異常后,手動修改配置中心的值,使得提前准備的降級預案生效。比如正常情況下我們會先讀緩存,如果緩存中沒有就嘗試從數據庫讀取,服務降級后,當緩存無法命中時,直接返回默認值,簡化功能。不過需要注意,有些情況操作生效時間不是實時的,客戶端會緩存第一次加載的配置,然后每隔一段時間就同步一次,甚至需要重啟APP才能生效,必要性只能讓客服引導用戶重啟APP。
再來看看自動生效。一般做法是,在接口定義時,定義標明好失敗或者超時返回的響應碼和數據。有時我們會返回托底跳轉鏈接給前端,讓前端重定向加載托底頁面。或者平時讓前端一次性分別請求正常的鏈接和托底的鏈接,當正常的請求響應異常時就展示托底的數據,這種方案雖然每次都是經常兩次,但是托底方案一般是輕量級的,所以也不失為一種策略。
那服務降級或者托底方案應該怎么做呢?
如果是核心流程,比如下單或者支付類不可或缺的流程,降級預案一般是在負載均衡Nginx中使用Lua腳本檢測CPU使用率,當達到閥值時開啟限流,讓用戶排隊。如果是非核心流程,比如領卷中心交互型的,可以設置用戶點擊必彈“已搶完”提示,總比功能缺陷直接暴露給用戶好。非核心流程中的不那么重要的服務,我們會直接關閉掉,比如紅點提醒、猜你喜歡。還有一種比較特殊,它和用戶日常操作強關聯的,比如該服務平時展示的列表都是用戶主動關注的,比如關注的達人最近發布的好文。那我們就每天同步存儲一份有界的無狀態的列表,當出現異常時就展示昨天的,這是在降低數據的一致性。這里我強調的是無狀態的,因為我們需要避免展示過期的數據,不然顯得很唐突和怪異。比如發現的京品推薦官,降級時會顯示回放列表。
最后再來看看幾個注意事項。
第一:周知。一個主入口里面會有很多的Tab,當默認Tab的服務短時間無法恢復時,往往會改變全部用戶的或者部分用戶的默認Tab,此時會和業務方提前溝通好,確保能承載相應的流量,防止雪崩效應。另外一個就是當發生異常時,及時和領導報備,不要一個人埋頭苦干,其他人或許會有更佳的止損方案。
第二:事務補償。當然每個業務的預案千差萬別,有些還得准備好補償機制。比如京東優惠小程序中組團領京豆,當成團而沒有給用戶京豆余額增加時,需要能及時手動補發。
第三:入口隱藏。有些情況,我們會隱藏入口或者入口明確提示用戶該功能升級維護中,避免出現用戶點擊了以為生效了,但是實際上是不會生效的情況,造成用戶損失。比如之前京東的東東農場中定時領取水滴,業務調整了但是入口沒有做調整,導致了大量的客戶投訴。
第四:降級來源和正常數據來源分開。
第五:緊急擴容。當服務負載過高,我們可能臨時申請容器抗壓。在京東,在大促高流量節點期間,上線變更需要多級審批。突發情況下我們為了減少上線流程時間,會在預發布分組發布線上配置的服務,因為預發布分組是無須領導審批的。
好,我今天分享了在京東是如何做服務級級的。如果有幫助到你,歡迎分享給你朋友們或者點個在看。
BLOG地址:www.liangsonghua.me
關注WX:松花皮蛋的黑板報,獲取更多精彩!
WX介紹:分享在京東工作的技術感悟,還有JAVA技術和業內最佳實踐,大部分都是務實的、能看懂的、可復現的
