高并發(fā)中的 限流、熔斷、降級、預(yù)熱、背壓!
首先,我們需要明確一下這幾個名詞出現(xiàn)的場景:分布式高并發(fā)環(huán)境。如果你的產(chǎn)品賣相不好,沒人鳥它,那它就用不著這幾個屬性。不需要任何加成,低并發(fā)系統(tǒng)就能工作的很好。
分布式系統(tǒng)是一個整體,調(diào)用關(guān)系錯綜復(fù)雜,其中某個資源異常,大概率會造成級聯(lián)故障。當(dāng)系統(tǒng)處于超負(fù)荷的壓力之下,容器或者宿主機(jī),將表現(xiàn)的異乎尋常的脆弱。load飆升、拒絕響應(yīng),甚至于雪崩,造成的后果都比較嚴(yán)重。
鑒于分布式系統(tǒng)病嬌娘樣式的反應(yīng),我們有各種手段來處理這些異常狀況。接下來,我們將簡要介紹一下這些場景,還有常用的手段。
1. 限流
“我的貼子被限流了!” 即使不是互聯(lián)網(wǎng)從業(yè)人員,也能言之鑿鑿的說出這樣的話。當(dāng)他這么說的時候,他并不是在說高并發(fā)中的限流,它只是邏輯意義上的。
web開發(fā)中,tomcat默認(rèn)是200個線程池,當(dāng)更多的請求到來,沒有新的線程能夠去處理這個請求,那這個請求將會一直等待在瀏覽器方。表現(xiàn)的形式是,瀏覽器一直在轉(zhuǎn)圈(還沒超過acceptCount),即使你請求的是一個簡單的Hello world。
你可以把這個過程,也看作是限流。它在本質(zhì)上,是設(shè)置一個資源數(shù)量上限,超出這個上限的請求,將被緩沖,或者直接失敗。
對于高并發(fā)場景下的限流來說,它有特殊的含義:它主要是用來保護(hù)底層資源的。如果你想要調(diào)用某些服務(wù),你需要首先獲取調(diào)用它的許可。限流一般由服務(wù)提供方來提供,對調(diào)用方能夠做事的能力進(jìn)行限制。
比如,某個服務(wù)為A、B、C都提供了服務(wù),但根據(jù)提前申請的流量預(yù)估,限制A服務(wù)的請求為1000/秒、B服務(wù)2000/秒,C服務(wù)1w/秒。在同一時刻,某些客戶端可能會出現(xiàn)被拒絕的請求,而某些客戶端能夠正常運行,限流被看作是服務(wù)端的自我保護(hù)能力。
常見的限流算法有:計數(shù)器、漏桶、令牌桶等。但計數(shù)器算法無法實現(xiàn)平滑的限流,在實際應(yīng)用中使用較少。
2. 熔斷
通常來說,皇帝在微服務(wù)里想夜生活過得舒服,能夠大刀闊斧單刀直入,不因私事丟江山,就不得不靠熔斷大總管。熔斷的作用,主要是為了避免服務(wù)的雪崩。
如圖,A→B→C互相依次調(diào)用,但C項目很可能出現(xiàn)問題(流量過大或者報錯等),就會引發(fā)線程一直進(jìn)行等待,導(dǎo)致拖垮整個鏈路層,線程資源耗盡。
意如其名,熔斷就像是保險絲,超過負(fù)載了保險絲就燒掉了。當(dāng)然,當(dāng)后端服務(wù)緩和的時候,我們還可以再把它接上。熔斷功能一般由調(diào)用端提供,用在不太重要的旁路請求上,避免這些不重要的服務(wù)因為異?;蛘叱瑫r,影響正常的、重要的業(yè)務(wù)邏輯
在實現(xiàn)上,我們可以把熔斷看作是一種代理模式。當(dāng)熔斷打開的時候,服務(wù)將暫停對其保護(hù)資源的訪問,并返回固定的或者不產(chǎn)生遠(yuǎn)程調(diào)用的默認(rèn)結(jié)果。
3. 降級
降級是一個比較模糊的說法。限流、熔斷,在一定程度上,也可以看作是降級的一種。但通常所說的降級,切入的層次更加高級一些。
降級一般考慮的是分布式系統(tǒng)的整體性,從源頭上切斷流量的來源。比如在雙11的時候,為了保證交易系統(tǒng),將會暫停一些不重要的服務(wù),以免產(chǎn)生資源爭占。服務(wù)降級有人工參與,人為使得某些服務(wù)不可用,多屬于一種業(yè)務(wù)降級方式。
在什么地方最適合做降級呢?就是入口。比如Nginx,比如DNS等。
在某些互聯(lián)網(wǎng)應(yīng)用中,會存在MVP(Minimum Viable Product)這個概念,意為最小化可行產(chǎn)品,它的SLA要求非常高。圍繞著最小可行性產(chǎn)品,會有一系列的服務(wù)拆分操作,當(dāng)然某些情況甚至需要重寫。
比如,一個電商系統(tǒng),在極端情況下,只需要把商品顯示出來,把商品賣出去就行。其他一些支撐性的系統(tǒng),比如評論、推薦等,都可以臨時關(guān)掉。在物理部署和調(diào)用關(guān)系上,就要考慮這些情況。
4. 預(yù)熱
請看下面一種情況。
一個高并發(fā)環(huán)境下的DB,進(jìn)程死亡后進(jìn)行重啟。由于業(yè)務(wù)處在高峰期間,上游的負(fù)載均衡策略發(fā)生了重分配。剛剛啟動的DB瞬間接受了1/3的流量,然后load瘋狂飆升,直至再無響應(yīng)。
原因就是:新啟動的DB,各種Cache并沒有準(zhǔn)備完畢,系統(tǒng)狀態(tài)與正常運行時截然不同??赡芷匠?/10的量,就能夠把它帶入死亡。
同理,一個剛剛啟動的JVM進(jìn)程,由于字節(jié)碼并未被JIT編譯器優(yōu)化,在剛啟動的時候,所有接口的響應(yīng)時間都比較慢。如果調(diào)用它的負(fù)載均衡組件,并沒有考慮這種剛啟動的情況,1/n的流量被正常路由到這個節(jié)點,就很容易出現(xiàn)問題。
所以,我們希望負(fù)載均衡組件,能夠依據(jù)JVM進(jìn)程的啟動時間,動態(tài)的慢慢加量,進(jìn)行服務(wù)預(yù)熱,直到達(dá)到正常流量水平。
5. 背壓
考慮一下下面兩種場景:
沒有限流。請求量過高,有多少收多少,極容易造成后端服務(wù)崩潰或者內(nèi)存溢出
傳統(tǒng)限流。你強行規(guī)定了某個接口最大的承受能力,超出了直接拒絕,但此時后端服務(wù)是有能力處理這些請求的
如何動態(tài)的修改限流的值?這就需要一套機(jī)制。調(diào)用方需要知道被調(diào)用方的處理能力,也就是被調(diào)用方需要擁有反饋的能力。背壓,英文Back Pressure,其實是一種智能化的限流,指的是一種策略。
背壓思想,被請求方不會直接將請求端的流量直接丟掉,而是不斷的反饋自己的處理能力。請求端根據(jù)這些反饋,實時的調(diào)整自己的發(fā)送頻率。比較典型的場景,就是TCP/IP中使用滑動窗口來進(jìn)行流量控制。
反應(yīng)式編程(Reactive)是觀察者模式的集大成者。它們大多使用事件驅(qū)動,多是非阻塞的彈性應(yīng)用,基于數(shù)據(jù)流進(jìn)行彈性傳遞。在這種場景下,背壓實現(xiàn)就簡單的多。
背壓,讓系統(tǒng)更穩(wěn)定,利用率也更高,它本身擁有更高的彈性和智能。
總結(jié)
簡單總結(jié)一下:
限流 規(guī)定一個上限,流量超過系統(tǒng)承載能力時,會直接拒絕服務(wù)
熔斷 不因底層旁路應(yīng)用的故障,造成系統(tǒng)雪崩。欲練此功,必先自宮
降級 從請求入口,大范圍的滅掉過載請求
預(yù)熱 給系統(tǒng)一些啟動預(yù)熱時間,加載緩存,避免資源死鎖
背壓 被調(diào)用方反饋自己的能力給調(diào)用方。溫柔的調(diào)用,需要堅實的溝通
簡單來講,只要流量不進(jìn)系統(tǒng),什么都好說,降級是最威猛最霸道的手段;一旦流量進(jìn)入系統(tǒng),就要接受系統(tǒng)內(nèi)一系列規(guī)則的制約,其中限流是最直接的手段,將請求攔在外面。雖然用戶的請求失敗了,但我的系統(tǒng)還能活;沒有熔斷的系統(tǒng)就很兇殘,很容易讓三流功能影響主要功能,所以要在合適的時候打開它;至于預(yù)熱,不過是在愛情火花前的一系列前戲,直到服務(wù)的巔峰狀態(tài);當(dāng)然,相對于請求扔出去就不管的模式,如果被調(diào)用方能夠反饋自己的狀態(tài),那么請求方就可以根據(jù)需要加大或者縮減馬力,這就是背壓的思想。
這些手段,都是在有限的資源下,有效的處理手段。但如果公司有錢,有彈性處理手段,這些都會變成輔助手段。畢竟,當(dāng)所有的服務(wù),能夠?qū)⒆约旱臓顟B(tài),反饋到監(jiān)控中心,監(jiān)控中心能夠?qū)崿F(xiàn)彈性擴(kuò)容。只要服務(wù)拆分的滿足水平擴(kuò)展,我們只需要增加實例就夠了。
作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。