- 注:文章來源:極客時間的專欄《從0開始學架構》
導致介面級故障的原因
內部原因
- 程式bug導致死迴圈
- 某個介面導致資料庫慢查詢
- 程式邏輯不完善導致耗盡記憶體等
外部原因
- 黑客攻擊、促銷或者搶購引入了超出平時幾倍甚至幾十倍的使用者
- 第三方系統大量請求
- 第三方系統響應緩慢等
解決介面故障的核心思想
- 優先保證核心業務和優先保證絕大部分使用者
- 丟車保帥,優先保證核心業務
降級
- 降級指系統將某些業務或者介面的功能降低,可以是隻提供部分功能,也可以是完全停掉所有功能
案例
- 雙11,訂單暫時不允許修改收貨地址
- 論壇,降級為只能看帖子,不能發帖子
- App的日誌上傳介面,可以完全停掉一段時間,這段時間內APP都不能上傳日誌
常見的實現降級的方式有:
- 系統後門降級
例如,系統提供一個降級URL,當訪問這個URL時,就相當於執行降級指令,具體的降級指令通過URL的引數傳入即可
缺點:安全隱患,伺服器數量多,需要一臺一臺去操作
- 獨立降級系統
將降級操作獨立到一個單獨的系統中,可以實現複雜的許可權管理、批量操作等功能。其基本架構如下:
熔斷
- 降級的目的是應對系統自身的故障,而熔斷的目的是應對依賴的外部系統故障的情況
案例
- A服務的X功能依賴B服務的某個介面,當B服務的介面響應很慢的時候,A服務的X功能響應肯定被拖慢,進一步導致A服務的執行緒都被卡在X功能處理上,此時A服務的其他功能都會被卡住或者響應非常慢
- 加入熔斷機制後,A服務不再請求B服務這個介面,A服務內部只要發現是請求B服務的這個介面就立即返回錯誤,從而避免A服務整個被拖慢甚至拖死
實現
- 關鍵是需要有一個統一的API呼叫層,由API呼叫層來進行取樣或者統計,如果介面呼叫散落在程式碼各處就沒法進行統一處理了
- 另一個關鍵是閾值的設計,例如1分鐘內30%的請求響應時間超過1秒就熔斷,這個策略的“1分鐘”“30%”“1秒”都對最終的熔斷效果有影響
- 實踐中一般都是先根據分析再確定閾值,然後上線觀察效果,再進行調優
限流
- 降級是從系統功能優先順序的角度考慮如何應對故障,而限流則是從使用者訪問壓力的角度來考慮如何應對故障
- 限流指只允許系統能夠承受的流量進來,超出系統訪問能力的請求將被丟棄
常見的限流方式
- 基於請求限流
是指從外部訪問的請求角度考慮限流
常見方式:限制總量、限制時間量
限制總量:限制某個指標的累積上限
例如,某個直播間限制總使用者數上限為100萬,超過後無法進入;搶購活動商品數量100個,限制參與使用者1萬個,超過1萬個後直接拒絕
限制時間量:限制一段時間內某個指標的上限
例如,1分鐘內只允許10000個使用者訪問,每秒請求峰值最高為10萬
缺點:閾值難於確定
- 基於資源限流
是指從系統內部考慮的,找到系統內部影響效能的關鍵資源,對其使用上限進行限制
常見的內部資源:連線數、檔案控制程式碼、執行緒數、請求佇列等
例如,採用Netty來實現伺服器,每個進來的請求都先放入一個佇列,業務執行緒再從佇列讀取請求進行處理,佇列長度最大值為10000,佇列滿了就拒絕後面的請求;也可以根據CPU的負載或者佔用率進行限流,當CPU的佔用率超過80%的時候就開始拒絕新的請求
缺點:難於確定關鍵資源及其閾值
實現方案:逐步調優,開始時先根據推斷選擇某個關鍵資源和閾值,然後測試驗證,再上線觀察,不合理再優化。
排隊
-
排隊是限流的一個變種,限流是直接拒絕使用者,排隊是讓使用者等待一段時間
-
由於排隊需要臨時快取大量的業務請求,單個系統內部無法快取這麼多資料,一般情況下,排隊需要用獨立的系統去實現,例如使用Kafka這類訊息佇列來快取使用者請求
-
排隊模組
將請求以先入先出的方式儲存下來,每一個參加秒殺的商品儲存一個佇列
- 排程模組
負責排隊模組到服務模組的動態排程,不斷檢查服務模組,一旦處理能力有空閒,就從排隊佇列頭上把使用者訪問資源請求調入服務模組,並負責向服務模組分發請求
- 服務模組
負責呼叫真正業務來處理服務,並返回處理結果,呼叫排隊模組的介面回寫業務處理結果
注:有興趣瞭解極客時間專欄的同學,可以檢視極客時間專欄—可提供返現服務