流量洪峰下做好高服務(wù)質(zhì)量的架構(gòu)是件具備挑戰(zhàn)的事情,本文詳細(xì)闡述了從Google SRE的系統(tǒng)方法論以及實(shí)際業(yè)務(wù)的應(yīng)對過程中出發(fā),一些體系化的可用性設(shè)計(jì)。對我們了解系統(tǒng)的全貌、上下游的聯(lián)防有更進(jìn)一步的幫助。
一、負(fù)載均衡
負(fù)載均衡具體分成兩個(gè)方向,一個(gè)是前端負(fù)載均衡,另一個(gè)是數(shù)據(jù)中心內(nèi)部的負(fù)載均衡。
前端負(fù)載均衡方面,一般而言用戶流量訪問層面主要依據(jù)DNS,希望做到最小化用戶請求延遲。將用戶流量最優(yōu)地分布在多個(gè)網(wǎng)絡(luò)鏈路上、多個(gè)數(shù)據(jù)中心、多臺服務(wù)器上,通過動(dòng)態(tài)CDN的方案達(dá)到最小延遲。
用戶流量會先流入BFE的前端接入層,第一層的BFE實(shí)際上起到一個(gè)路由的作用,盡可能選擇跟接入節(jié)點(diǎn)比較近的一個(gè)機(jī)房,用來加速用戶請求。然后通過API網(wǎng)關(guān)轉(zhuǎn)發(fā)到下游的服務(wù)層,可能是內(nèi)部的一些微服務(wù)或者業(yè)務(wù)的聚合層等,最終構(gòu)成一個(gè)完整的流量模式。
基于此,前端服務(wù)器的負(fù)載均衡主要考慮幾個(gè)邏輯:
第一,盡量選擇最近節(jié)點(diǎn);
第二,基于帶寬策略調(diào)度選擇API進(jìn)入機(jī)房;
第三,基于可用服務(wù)容量平衡流量。
數(shù)據(jù)中心內(nèi)部的負(fù)載均衡方面,理想情況下最忙和最不忙的節(jié)點(diǎn)所消耗的CPU相差幅度較小。但如果負(fù)載均衡沒做好,情況可能相差甚遠(yuǎn)。由此可能導(dǎo)致資源調(diào)度、編排的困難,無法合理分配容器資源。
因此,數(shù)據(jù)中心內(nèi)部負(fù)載均衡主要考慮:
均衡流量分發(fā);
可靠識別異常節(jié)點(diǎn);
scale-out,增加同質(zhì)節(jié)點(diǎn)以擴(kuò)容;
減少錯(cuò)誤,提高可用性。
我們此前通過同質(zhì)節(jié)點(diǎn)來擴(kuò)容就發(fā)現(xiàn),內(nèi)網(wǎng)服務(wù)出現(xiàn)CPU占用率過高的異常,通過排查發(fā)現(xiàn)背后RPC點(diǎn)到點(diǎn)通信間的 health check 成本過高,產(chǎn)生了一些問題。另外一方面,底層的服務(wù)如果只有單套集群,當(dāng)出現(xiàn)抖動(dòng)的時(shí)候故障面會比較大,因此需要引入多集群來解決問題。
通過實(shí)現(xiàn) client 到 backend 的子集連接,我們做到了將后端平均分配給客戶端,同時(shí)可以處理節(jié)點(diǎn)變更,持續(xù)不斷均衡連接,避免大幅變動(dòng)。多集群下,則需要考慮集群遷移的運(yùn)維成本,同時(shí)集群之間業(yè)務(wù)的數(shù)據(jù)存在較小的交集。
回到CPU忙時(shí)、閑時(shí)占用率過大的問題,我們會發(fā)現(xiàn)這背后跟負(fù)載均衡算法有關(guān)。
第一個(gè)問題,對于每一個(gè)qps,實(shí)際上就是每一個(gè)query、查詢、API請求,它們的成本是不同的。節(jié)點(diǎn)與節(jié)點(diǎn)之間差異非常大,即便你做了均衡的流量分發(fā),但是從負(fù)載的角度來看,實(shí)際上還是不均勻的。
第二個(gè)問題,存在物理機(jī)環(huán)境上的差異。因?yàn)槲覀兺ǔ6际欠帜瓴少彿?wù)器,新買的服務(wù)器通常主頻CPU會更強(qiáng)一些,所以服務(wù)器本質(zhì)上很難做到強(qiáng)同質(zhì)。
基于此,參考JSQ(最閑輪訓(xùn))負(fù)載均衡算法帶來的問題,發(fā)現(xiàn)缺乏的是服務(wù)端全局視圖,因此我們的目標(biāo)需要綜合考慮負(fù)載和可用性。我們參考了《The power of two choices in randomized load balancing》的思路,使用the choice-of-2算法,隨機(jī)選取的兩個(gè)節(jié)點(diǎn)進(jìn)行打分,選擇更優(yōu)的節(jié)點(diǎn):
選擇backend:CPU,client:health、inflight、latency作為指標(biāo),使用一個(gè)簡單的線性方程進(jìn)行打分;
對新啟動(dòng)的節(jié)點(diǎn)使用常量懲罰值(penalty),以及使用探針方式最小化放量,進(jìn)行預(yù)熱;
打分比較低的節(jié)點(diǎn),避免進(jìn)入“永久黑名單”而無法恢復(fù),使用統(tǒng)計(jì)衰減的方式,讓節(jié)點(diǎn)指標(biāo)逐漸恢復(fù)到初始狀態(tài)(即默認(rèn)值)。
通過優(yōu)化負(fù)載均衡算法以后,我們做到了比較好的收益。
二、限流
避免過載,是負(fù)載均衡的一個(gè)重要目標(biāo)。隨著壓力增加,無論負(fù)載均衡策略如何高效,系統(tǒng)某個(gè)部分總會過載。我們優(yōu)先考慮優(yōu)雅降級,返回低質(zhì)量的結(jié)果,提供有損服務(wù)。在最差的情況,妥善的限流來保證服務(wù)本身穩(wěn)定。
限流這塊,我們認(rèn)為主要關(guān)注以下幾點(diǎn):
一是針對qps的限制,帶來請求成本不同、靜態(tài)閾值難以配置的問題;
二是根據(jù)API的重要性,按照優(yōu)先級丟棄;
三是給每個(gè)用戶設(shè)置限制,全局過載發(fā)生時(shí)候,針對某些“異?!边M(jìn)行控制非常關(guān)鍵;
四是拒絕請求也需要成本;
五是每個(gè)服務(wù)都配置限流帶來的運(yùn)維成本。
在限流策略上,我們首先采用的是分布式限流。我們通過實(shí)現(xiàn)一個(gè)quota-server,用于給backend針對每個(gè)client進(jìn)行控制,即backend需要請求quota-server獲取quota。
這樣做的好處是減少請求Server的頻次,獲取完以后直接本地消費(fèi)。算法層面使用最大最小公平算法,解決某個(gè)大消耗者導(dǎo)致的饑餓。
在客戶端側(cè),當(dāng)出現(xiàn)某個(gè)用戶超過資源配額時(shí),后端任務(wù)會快速拒絕請求,返回“配額不足”的錯(cuò)誤,有可能后端忙著不停發(fā)送拒絕請求,導(dǎo)致過載和依賴的資源出現(xiàn)大量錯(cuò)誤,處于對下游的保護(hù)兩種狀況,我們選擇在client側(cè)直接進(jìn)行流量,而不發(fā)送到網(wǎng)絡(luò)層。
我們在Google SRE里學(xué)到了一個(gè)有意思的公式,max(0, (requests- K*accepts) / (requests + 1))。通過這種公式,我們可以讓client直接發(fā)送請求,一旦超過限制,按照概率進(jìn)行截流。
在過載保護(hù)方面,核心思路就是在服務(wù)過載時(shí),丟棄一定的流量,保證系統(tǒng)臨近過載時(shí)的峰值流量,以求自保護(hù)。常見的做法有基于CPU、內(nèi)存使用量來進(jìn)行流量丟棄;使用隊(duì)列進(jìn)行管理;可控延遲算法:CoDel 等。
簡單來說,當(dāng)我們的CPU達(dá)到80%的時(shí)候,這個(gè)時(shí)候可以認(rèn)為它接近過載,如果這個(gè)時(shí)候的吞吐達(dá)到100,瞬時(shí)值的請求是110,我就可以丟掉這10個(gè)流量,這種情況下服務(wù)就可以進(jìn)行自保護(hù),我們基于這樣的思路最終實(shí)現(xiàn)了一個(gè)過載保護(hù)的算法。
我們使用CPU的滑動(dòng)均值(CPU > 800 )作為啟發(fā)閾值,一旦觸發(fā)就進(jìn)入到過載保護(hù)階段。算法為:(MaxPass * AvgRT) < InFlight。其中MaxPass、AvgRT都為觸發(fā)前的滑動(dòng)時(shí)間窗口的統(tǒng)計(jì)值。
限流效果生效后,CPU會在臨界值(800)附近抖動(dòng),如果不使用冷卻時(shí)間,那么一個(gè)短時(shí)間的CPU下降就可能導(dǎo)致大量請求被放行,嚴(yán)重時(shí)會打滿CPU。在冷卻時(shí)間后,重新判斷閾值(CPU > 800 ),是否持續(xù)進(jìn)入過載保護(hù)。
三、重試
流量的走向,一般會從BFE到SLB然后經(jīng)過API網(wǎng)關(guān)再到BFF、微服務(wù)最后到數(shù)據(jù)庫,這個(gè)過程要經(jīng)過非常多層。在我們的日常工作中,當(dāng)請求返回錯(cuò)誤,對于backend部分節(jié)點(diǎn)過載的情況下,我們應(yīng)該怎么做?
首先我們需要限制重試的次數(shù),以及基于重試分布的策略;
其次,我們只應(yīng)該在失敗層進(jìn)行重試,當(dāng)重試仍然失敗時(shí),我們需要全局約定錯(cuò)誤碼,避免級聯(lián)重試;
此外,我們需要使用隨機(jī)化、指數(shù)型遞增的充實(shí)周期,這里可以參考Exponential Backoff和Jitter;
最后,我們需要設(shè)定重試速率指標(biāo),用于診斷故障。
而在客戶端側(cè),則需要做限速。因?yàn)橛脩艨偸菚l繁嘗試去訪問一個(gè)不可達(dá)的服務(wù),因此客戶端需要限制請求頻次,可以通過接口級別的error_details,掛載到每個(gè)API返回的響應(yīng)里。
四、超時(shí)
我們之前講過,大部分的故障都是因?yàn)槌瑫r(shí)控制不合理導(dǎo)致的。首當(dāng)其沖的是高并發(fā)下的高延遲服務(wù),導(dǎo)致client堆積,引發(fā)線程阻塞,此時(shí)上游流量不斷涌入,最終引發(fā)故障。所以,從本質(zhì)上理解超時(shí)它實(shí)際就是一種Fail Fast的策略,就是讓我們的請求盡可能消耗,類似這種堆積的請求基本上就是丟棄掉或者消耗掉。
另一個(gè)方面,當(dāng)上游超時(shí)已經(jīng)返回給用戶后,下游可能還在執(zhí)行,這就會引發(fā)資源浪費(fèi)的問題。
再一個(gè)問題,當(dāng)我們對下游服務(wù)進(jìn)行調(diào)優(yōu)時(shí),到底如何配置超時(shí),默認(rèn)值策略應(yīng)該如何設(shè)定?生產(chǎn)環(huán)境下經(jīng)常會遇到手抖或者錯(cuò)誤配置導(dǎo)致配置失敗、出現(xiàn)故障的問題。所以我們最好是在框架層面做一些防御性的編程,讓它盡可能讓取在一個(gè)合理的區(qū)間內(nèi)。
進(jìn)程內(nèi)的超時(shí)控制,關(guān)鍵要看一個(gè)請求在每個(gè)階段(網(wǎng)絡(luò)請求)開始前,檢查是否還有足夠的剩余來處理請求。另外,在進(jìn)程內(nèi)可能會有一些邏輯計(jì)算,我們通常認(rèn)為這種時(shí)間比較少,所以一般不做控制。
現(xiàn)在很多RPC框架都在做跨進(jìn)程超時(shí)控制,為什么要做這個(gè)?跨進(jìn)程超時(shí)控制同樣可以參考進(jìn)程內(nèi)的超時(shí)控制思路,通過RPC的源數(shù)據(jù)傳遞,把它帶到下游服務(wù),然后利用配額繼續(xù)傳遞,最終使得上下游鏈路不超過一秒。
審核編輯 黃宇
-
RPC
+關(guān)注
關(guān)注
0文章
113瀏覽量
12198 -
架構(gòu)
+關(guān)注
關(guān)注
1文章
532瀏覽量
26506
發(fā)布評論請先 登錄
高鐵站智能變電站方案:構(gòu)建高效安全電力
Arm Unlocked 2025深圳站圓滿落幕
校園科普氣象站:技術(shù)賦能下的自然探索課堂
光伏自動(dòng)氣象站技術(shù)架構(gòu)與發(fā)電效率保障應(yīng)用
分布式光伏環(huán)境監(jiān)測站的技術(shù)架構(gòu)與應(yīng)用實(shí)踐
企業(yè)級HDFS高可用與YARN資源調(diào)度方案
華納云:海外服務(wù)器負(fù)載均衡與高可用架構(gòu)設(shè)計(jì)
香港服務(wù)器部署Windows集群服務(wù)的網(wǎng)絡(luò)拓?fù)湓O(shè)計(jì)與實(shí)現(xiàn)-高可用性架構(gòu)方案
光伏實(shí)驗(yàn)氣象站的技術(shù)架構(gòu)與應(yīng)用實(shí)踐
深入剖析RabbitMQ高可用架構(gòu)設(shè)計(jì)
QNAP 正式推出 NAS 雙機(jī)架構(gòu)的高可用性解決方案,打造不中斷的儲存環(huán)境
介紹三種常見的MySQL高可用方案
MYSQL集群高可用和數(shù)據(jù)監(jiān)控平臺實(shí)現(xiàn)方案
阿里國際站“八先過海”計(jì)劃助力B2B商家出海
TMS320C3x通用應(yīng)用用戶指南

B站高可用用架構(gòu)實(shí)踐
評論