譯者 | 李睿
審校 | 重樓
研究表明,即使是最堅固、設(shè)計最精良的水壩也無法承受失控洪水的破壞力。同樣,在分布式系統(tǒng)的場景中,未經(jīng)限制的調(diào)用者通常會使整個系統(tǒng)不堪重負,并導致級聯(lián)故障。如果沒有適當?shù)姆雷o措施,重試風暴有可能使整個服務(wù)崩潰。本文將探討服務(wù)何時應該考慮對其調(diào)用者應用背壓(Backpressure),如何應用,以及調(diào)用者可以做些什么來處理背壓。
背壓
顧名思義,背壓是分布式系統(tǒng)中的一種機制,指的是系統(tǒng)限制數(shù)據(jù)消耗或產(chǎn)生速度的能力,以防止自身或其下游組件過載。系統(tǒng)對其調(diào)用者施加背壓并不總是顯式的,例如以節(jié)流或減少負載的形式,但有時也是隱式的,例如通過增加服務(wù)請求的延遲而不顯式地減慢自己的系統(tǒng)。隱式和顯式背壓都是為了降低調(diào)用者的速度,無論是調(diào)用者表現(xiàn)不佳,還是服務(wù)本身狀態(tài)不佳,需要時間來恢復。
需要背壓
以下舉例說明系統(tǒng)何時需要施加背壓。在這個例子中,正在構(gòu)建一個包含三個主要組件的控制平臺服務(wù):一個接收客戶請求的前端,一個緩沖客戶請求的內(nèi)部隊列,以及一個從隊列讀取消息并寫入數(shù)據(jù)庫以實現(xiàn)持久性的消費者應用程序。
圖1控制平臺示例
(1)生產(chǎn)者與消費者不匹配
設(shè)想這樣一種場景,參與者/客戶以極高的頻率訪問前端,導致內(nèi)部隊列已滿或?qū)懭霐?shù)據(jù)庫的工作線程很忙,進而造成隊列滿載。在這種情況下,請求不能排隊,因此與其放棄客戶請求,不如提前通知客戶。這種不匹配可能由于各種原因而發(fā)生,例如傳入流量激增或系統(tǒng)出現(xiàn)小故障,其中消費者服務(wù)曾經(jīng)一度停機,但現(xiàn)在必須增加額外的工作時間,以有效清理并解決在停機期間所形成的工作積壓問題。
(2)資源約束和級聯(lián)故障
設(shè)想這樣一種場景,隊列接近其容量的100%,而平時在50%左右。為了匹配這種傳入速率的增加,可以擴展消費者應用程序,并開始以更高的速率寫入數(shù)據(jù)庫。但是,數(shù)據(jù)庫因無法處理這種增長(例如每秒寫入次數(shù)的限制)而崩潰。這種故障將導致整個系統(tǒng)癱瘓,并增加平均恢復時間(MTTR)。在這種情況下,在適當?shù)牡胤绞┘颖硥鹤兊弥陵P(guān)重要。
(3)錯過服務(wù)水平協(xié)議(SLA)
考慮這樣一種場景:寫入數(shù)據(jù)庫的數(shù)據(jù)每5分鐘處理一次,另一個應用程序會監(jiān)聽這些數(shù)據(jù)以保持自身更新?,F(xiàn)在,如果系統(tǒng)由于某種原因無法滿足SLA,例如隊列已滿90%,可能需要10分鐘才能清除所有消息,那么最好采用背壓技術(shù)??梢酝ㄖ蛻魧e過SLA,并建議他們稍后再試,或者通過從隊列中刪除非緊急請求來應用背壓,以滿足關(guān)鍵事件/請求的SLA。
背壓的挑戰(zhàn)
根據(jù)上述內(nèi)容,似乎應該始終應用背壓,聽起來確實如此,主要的挑戰(zhàn)不是是否應該應用背壓,而是如何確定應用背壓的正確點,以及應用反壓力的機制,以滿足特定的服務(wù)/業(yè)務(wù)需求。
背壓迫使在吞吐量和穩(wěn)定性之間進行權(quán)衡,而負載預測的挑戰(zhàn)使這種權(quán)衡變得更加復雜。
確定背壓點
(1)查找瓶頸/薄弱環(huán)節(jié)
每個系統(tǒng)都存在瓶頸。有些瓶頸能夠自我承受和保護,而有些則不能。設(shè)想在一個系統(tǒng)中,其中龐大的數(shù)據(jù)平臺集群(數(shù)千臺主機)依賴于一個小型控制平臺集群(少于5臺主機)來接收存儲在數(shù)據(jù)庫中的配置,如上圖所示。大型集群很容易使小型集群不堪重負。在這種情況下,為了保護自己,小型集群應該具備對調(diào)用者應用背壓的機制。架構(gòu)中的另一個常見薄弱環(huán)節(jié)是對整個系統(tǒng)做出決策的集中式組件,例如反熵掃描器。如果它們失效,系統(tǒng)就永遠無法達到穩(wěn)定狀態(tài),甚至可能導致整個服務(wù)崩潰。
(2)使用系統(tǒng)動態(tài):監(jiān)測器/指標
另一種為系統(tǒng)找到回壓點的常見方法是設(shè)置適當?shù)?/span>監(jiān)測器/指標。持續(xù)監(jiān)控系統(tǒng)行為,包括隊列深度、CPU/內(nèi)存利用率和網(wǎng)絡(luò)吞吐量。利用這些實時數(shù)據(jù)來識別新出現(xiàn)的瓶頸,并相應地調(diào)整背壓點。通過指標或觀察者(例如跨不同系統(tǒng)組件的性能金絲雀)來創(chuàng)建綜合視圖,是了解系統(tǒng)是否處于壓力狀態(tài)并應對其用戶/調(diào)用者施加背壓的另一種方法。這些性能金絲雀(Performance Canaries)可以針對系統(tǒng)的不同方面進行隔離,以找到瓶頸。此外,擁有一個內(nèi)部資源使用情況的實時儀表板是另一種利用系統(tǒng)動態(tài)來發(fā)現(xiàn)關(guān)鍵點和采取更加積極主動措施的好方法。
(3)邊界:最小驚奇原則
對客戶來說,最明顯的是與他們互動的服務(wù)表面區(qū)域。通常是客戶用來為其請求提供服務(wù)的API。這也是客戶在出現(xiàn)背壓時最不會感到驚訝的地方,因為它清楚地表明系統(tǒng)處于壓力之下。它能夠以節(jié)流或減載的形式出現(xiàn)。同樣的原則可以在服務(wù)本身中跨不同的子組件和接口應用,它們通過這些子組件和界面相互交互。這些表面是施加背壓的最佳位置,有助于最大限度地減少混亂,使系統(tǒng)的行為更具可預測性。
如何在分布式系統(tǒng)中應用背壓
在上一節(jié)中,討論了如何找到正確的興趣點以施加背壓。一旦確定了這些點,以下是一些在實際中施加背壓的方法。
構(gòu)建顯式流控制
這個想法是讓調(diào)用者能夠看到隊列的大小,并根據(jù)它來控制調(diào)用速率。通過了解隊列大?。ɑ蛉魏纬蔀槠款i的資源),調(diào)用者可以增加或減少調(diào)用率,以避免系統(tǒng)過載。這種技術(shù)在多個內(nèi)部組件協(xié)同工作且盡可能不影響彼此的情況下特別有用。以下公式可以在任何時候用來計算調(diào)用者的速率。注:實際的調(diào)用速率將取決于各種其他因素,但以下這個公式應該能夠提供一個很好的思路。
CallRate_new = CallRate_normal * (1 - (Q_currentSize / Q_maxSize))
倒置責任
在某些系統(tǒng)中,可以改變調(diào)用者不直接地向服務(wù)發(fā)送請求的順序,而是讓服務(wù)請求在準備好提供服務(wù)時自行工作。這種技術(shù)使接收服務(wù)可以完全控制它可以做多少事情,并且可以根據(jù)其最新狀態(tài)動態(tài)更改請求大小??梢圆捎昧钆仆安呗裕渲薪邮辗?wù)填充令牌,并告訴調(diào)用者何時以及他們可以向服務(wù)器發(fā)送多少令牌。以下是調(diào)用者可以使用的一個示例算法:
# Service requests work if it has capacity
if Tokens_available > 0:
Work_request_size = min (Tokens_available, Work_request_size _max) # Request work, up to a maximum limit
send_request_to_caller(Work_request_size) # Caller sends work if it has enough tokens
if Tokens_available >= Work_request_size:
send_work_to_service(Work_request_size)
Tokens_available = Tokens_available – Work_request_size
# Tokens are replenished at a certain rate
Tokens_available = min (Tokens_available + Token_Refresh_Rate, Token_Bucket_size)
主動調(diào)整
有時,提前知道系統(tǒng)很快就會不堪重負,于是采取主動措施,例如要求調(diào)用者降低調(diào)用量,然后再慢慢增加。設(shè)想這樣一個場景:下游服務(wù)宕機并拒絕了所有請求。在此期間,將所有工作排在隊列中,現(xiàn)在準備按照SLA將其清空。但是,如果以高于正常速率的速度清空隊列,就有可能導致下游服務(wù)癱瘓。為了解決這個問題,可以主動限制調(diào)用者的請求量,或者與調(diào)用者溝通,要求其減少調(diào)用量,并慢慢放寬限制。
限流
限制服務(wù)能夠處理的請求數(shù)量,并丟棄超出這一數(shù)量的請求。限流可以在服務(wù)層面或API層面實施。這種限流是對調(diào)用者的一種直接反饋,提示其降低調(diào)用量??梢赃M一步采取優(yōu)先級限流或公平限流策略,以確保對客戶的影響降到最低。
減載
限流是當違反某些預定義的限制時丟棄請求。如果服務(wù)面臨過大壓力并決定主動放棄已經(jīng)承諾服務(wù)的請求,客戶請求仍然可以被丟棄。這種行為通常是服務(wù)保護自己并讓調(diào)用者知道它的最后手段。
結(jié)論
在分布式系統(tǒng)中,背壓是一個重要的挑戰(zhàn),它會嚴重影響系統(tǒng)的性能和穩(wěn)定性。了解背壓的原因和后果,以及掌握有效的管理技術(shù),對于構(gòu)建健壯且高性能的分布式系統(tǒng)至關(guān)重要。如果實施得當,背壓可以增強系統(tǒng)的穩(wěn)定性、可靠性和可擴展性,從而提升用戶體驗。如果處理不當,可能會削弱客戶信任,甚至導致系統(tǒng)不穩(wěn)定。通過仔細的系統(tǒng)設(shè)計和監(jiān)控主動應對背壓是維護系統(tǒng)健康的關(guān)鍵。雖然實施背壓可能涉及一些權(quán)衡,例如可能影響吞吐量,但從整體系統(tǒng)彈性和用戶滿意度來看,其帶來的好處是巨大的。
原文標題:Backpressure in Distributed Systems,作者:Rajesh Pandey