歡迎關注個人微訊號:石杉的架構筆記(id:shishan100)

週一至週五早8點半!精品技術文章準時送上!


往期文章



目錄

一、概述

二、業務場景

三、線上經驗—如何設定Hystrix執行緒池大小

四、線上經驗—如何設定請求超時時間

五、問題解決

六、總結



一、概述


上一篇文章講了一個朋友公司使用Spring Cloud架構遇到問題的一個真實案例,雖然不是什麼大的技術問題,但如果對一些東西理解的不深刻,還真會犯一些錯誤。



如果沒看過這篇的朋友,建議先看看:【雙11狂歡的背後】微服務註冊中心如何承載大型系統的千萬級訪問? 因為本文的案例背景會基於上一篇文章。



這篇文章我們來聊聊在微服務架構中,到底如何保證整套系統的高可用?



其實排除掉一些基礎設施的故障,比如說Redis叢集掛了,Elasticsearch叢集故障了,MySQL宕機了。



微服務架構自己本身最最核心的保障高可用的措施,就是兩個:


  1. 一個是基於Hystrix做資源隔離以及熔斷;


  2. 另一個是做備用降級方案。



如果資源隔離和降級都做的很完善,那麼在比如雙11的這種高併發場景下,雖然可能會出現個別的服務故障,但是絕對是不會蔓延到整個系統全部宕機的。



這裡大家如果忘了如何基於hystrix做資源隔離、熔斷以及降級的話,可以回顧一下文章:《 拜託!面試請不要再問我Spring Cloud底層原理 》




二、業務場景



好的,那我們這就來深入的分析一下,在實際生產系統中,hystrix的執行緒池以及超時時間,這兩個引數應該如何根據系統的負載設定到最佳的狀態?



大家首先回顧下面這張圖,這是上篇文章中說到的一個公司的系統。



核心服務A呼叫了核心服務B和C,在核心服務B響應過慢時,會導致核心服務A的某個執行緒池全部卡死。



但是此時因為你用了hystrix做了資源隔離,所以核心服務A是可以正常呼叫服務C的,那麼就可以保證使用者起碼是可以使用APP的部分功能的,只不過跟服務B關聯的頁面刷不出來,功能無法使用罷了。






當然這種情況在生產系統中,是絕對不被允許的,所以大家千萬讓上述情況發生。



在上一篇文章中,我們最終把系統優化成了下圖這樣,要保證一個hystrix執行緒池可以輕鬆處理每秒鐘的請求,同時還有合理的超時時間設定,避免請求太慢卡死執行緒。









三、線上經驗—如何設定Hystrix執行緒池大小



好,現在問題來了,在生產環境中,我們到底應該如何設定服務中每個hystrix執行緒池的大小,以及如何設定超時時間呢?



下面就是我們線上大量系統優化後的生產經驗總結:


假設你的服務A,每秒鐘會接收30個請求,同時會向服務B發起30個請求,然後每個請求的響應時長經驗值大概在200ms,那麼你的hystrix執行緒池需要多少個執行緒呢?



計算公式是:30(每秒請求數量) * 0.2(每個請求的處理秒數) + 4(給點緩衝buffer) = 10(執行緒數量)。



如果大家對上述公式存在疑問,不妨反過來推算一下,為什麼10個執行緒可以輕鬆抗住每秒30個請求?



一個執行緒200毫秒可以執行完一個請求,那麼一個執行緒1秒可以執行5個請求,理論上,只要6個執行緒,每秒就可以執行30個請求。



也就是說,執行緒裡的10個執行緒中,就6個執行緒足以抗住每秒30個請求了。剩下4個執行緒都在玩兒,空閒著。



那為啥要多搞4個執行緒呢?很簡單,因為你要留一點buffer空間。



萬一在系統高峰期,系統性能略有下降,此時不少請求都耗費了300多毫秒才執行完,那麼一個執行緒每秒只能處理3個請求了,10個執行緒剛剛好勉強可以hold住每秒30個請求。所以你必須多考慮留幾個執行緒。



老規矩,給大家來一張圖,直觀的感受一下。








四、線上經驗—如何設定請求超時時間


接著來,那麼請求的超時時間設定為多少?答案是300毫秒。



為啥呢?很簡單啊,兄弟!如果你的超時時間設定成了500毫秒,想想可能會有什麼後果?



考慮極端情況,如果服務B響應變慢,要500毫秒才響應,你一個執行緒每秒最多隻能處理2個請求了,10個執行緒只能處理20個請求。



而每秒是30個請求過來,結局會如何?咱們回看一下第一張圖就知道了,大量的執行緒會全部卡死,來不及處理那麼多請求,最後使用者會刷不出來頁面。


還是有點不理解?再給你一張圖,讓你感受一下這個不合理的超時時間導致的問題!









如果你的執行緒池大小和超時時間沒有配合著設定好,很可能會導致服務B短暫的效能波動,瞬間導致服務A的執行緒池卡死,裡面的執行緒要卡頓一段時間才能繼續執行下一個請求。



哪怕服務B的介面效能恢復到200毫秒以內了,服務A的執行緒池裡卡死的狀況也要好一會兒才能恢復過來。你的超時時間不合理的設定的越長,比如設定1秒、2秒,那麼這種卡死的情況就需要越長的時間來恢復。



所以說,此時你的超時時間就得設定成300毫秒,保證一個請求300毫秒內執行不完,立馬超時返回。



這樣執行緒池裡的執行緒不會長時間卡死,可以有條不紊的處理多出來的請求,大不了就是300毫秒內處理不完立即超時返回,但是執行緒始終保持可以執行的狀態。



這樣當服務B的介面效能恢復到200毫秒以內了,服務A的執行緒池裡的執行緒很快就可以恢復。



這就是生產系統上的hystrix引數設定優化經驗,你必須考慮到各種引數應該如何設定。



否則的話,很可能會出現上文那樣的情況,用了高大上的Spring Cloud,結果跟黑盒子一樣,莫名其妙系統故障,各種卡死,宕機什麼的。




五、問題解決


好了,我們繼續。如果現在這套系統每秒有6000請求,然後核心服務A一共部署了60臺機器,每臺機器就是每秒會收到100個請求,那麼此時你的執行緒池需要多少個執行緒?



很簡單了,10個執行緒抗30個請求,30個執行緒抗100請求,差不多了吧。



這個時候,你知道你的服務A的執行緒池,呼叫服務B的那個執行緒池,應該分配多少執行緒了吧?超時時間如何設定應該也知道了!



其實這個東西不是固定死的,但是你要知道他的計算方法,根據服務的響應時間、系統高峰QPS、有多少臺機器,來計算出來,執行緒池的大小以及超時時間!



設定完這些之後,就應該要考慮服務降級的事情了。



如果你的某個服務掛了,那麼你的hystrix會走熔斷器,然後就會降級,你需要考慮到各個服務的降級邏輯。



舉一些常見的例子:


  • 如果查詢資料的服務掛了,你可以查本地的快取


  • 如果寫入資料的服務掛了,你可以先把這個寫入操作記錄日誌到比如mysql裡,或者寫入MQ裡,後面再慢慢恢復


  • 如果redis掛了,你可以查mysql


  • 如果mysql掛了,你可以把操作日誌記錄到es裡去,後面再慢慢恢復資料。



具體用什麼降級策略,要根據業務來定,不是一成不變的。



六、總結


總結一下,排除那些基礎設施的故障,你要玩兒微服務架構的話,需要保證兩點:


  1. 首先你的hystrix資源隔離以及超時這塊,必須設定合理的引數,避免高峰期,頻繁的hystrix執行緒卡死


  1. 其次,針對個別的服務故障,要設定合理的降級策略,保證各個服務掛了,可以合理的降級,系統整體可用!




如有收穫,請幫忙轉發,您的鼓勵是作者最大的動力,謝謝!



一大波微服務、分散式、高併發、高可用原創系列文章正在路上:


兄弟,用大白話告訴你小白都能看懂的Hadoop架構原理敬請期待

大規模叢集下Hadoop的NameNode如何承載高併發訪問敬請期待


歡迎掃描下方二維碼,持續關注:


石杉的架構筆記(id:shishan100)

十餘年BAT架構經驗傾囊相授