當(dāng)資源成為瓶頸時(shí)钓简,服務(wù)框架需要對(duì)消費(fèi)者做限流油啤,啟動(dòng)流控保護(hù)機(jī)制。流量控制有多種策略,比較常用的有:針對(duì)訪問速率的靜態(tài)流控预皇、針對(duì)資源占用的動(dòng)態(tài)流控侈玄、針對(duì)消費(fèi)者并發(fā)連接數(shù)的連接控制和針對(duì)并行訪問數(shù)的并發(fā)控制。在實(shí)踐中吟温,各種流量控制策略需要綜合使用才能起到較好的效果序仙。
1. 靜態(tài)流控
靜態(tài)流控主要針對(duì)客戶端訪問速率進(jìn)行控制,它通常根據(jù)服務(wù)質(zhì)量等級(jí)協(xié)定(SLA)中約定的QPS做全局流量控制鲁豪,例如訂單服務(wù)的靜態(tài)流控閾值為100QPS诱桂,則無論集群有多少個(gè)訂單服務(wù)實(shí)例,它們總的處理速率之和不能超過100QPS呈昔。
1.1 傳統(tǒng)靜態(tài)流控設(shè)計(jì)方案
傳統(tǒng)的靜態(tài)流控設(shè)計(jì)采用安裝預(yù)分配方案挥等,在軟件安裝時(shí),根據(jù)集群服務(wù)節(jié)點(diǎn)個(gè)數(shù)和靜態(tài)流控閾值堤尾,計(jì)算每個(gè)服務(wù)節(jié)點(diǎn)分?jǐn)偟腝PS閾值肝劲,系統(tǒng)運(yùn)行時(shí),各個(gè)服務(wù)節(jié)點(diǎn)按照自己分配的閾值進(jìn)行流控郭宝,對(duì)于超出流控閾值的請(qǐng)求則拒絕訪問辞槐。
服務(wù)架構(gòu)啟動(dòng)時(shí),將本節(jié)點(diǎn)的靜態(tài)流控閾值加載到內(nèi)存中粘室,服務(wù)框架通過Handler攔截器在服務(wù)調(diào)用前做攔截計(jì)數(shù)榄檬。當(dāng)計(jì)數(shù)器在指定周期T到達(dá)QPS上線時(shí),啟動(dòng)流控衔统,拒絕新的請(qǐng)求消息接入鹿榜。
有兩點(diǎn)需要注意:
- 服務(wù)實(shí)例通常由多線程執(zhí)行,因此計(jì)數(shù)時(shí)需要考慮線程并發(fā)安全锦爵,可以使用Atomic原子類進(jìn)行原子操作舱殿。
- 到達(dá)流控閾值之后拒絕新的請(qǐng)求消息接入,不能拒絕后續(xù)的應(yīng)答消息险掀,否則這會(huì)導(dǎo)致客戶端超時(shí)或者觸發(fā)FailOver沪袭,增加服務(wù)端的負(fù)載。
1.2 傳統(tǒng)方案的缺點(diǎn)
靜態(tài)分配方案的最大缺點(diǎn)就是忽略了服務(wù)實(shí)例的動(dòng)態(tài)變化:
- 云端服務(wù)的彈性伸縮性是服務(wù)節(jié)點(diǎn)數(shù)處于動(dòng)態(tài)變化過程中樟氢,預(yù)分配方案行不通冈绊。
- 服務(wù)節(jié)點(diǎn)宕機(jī),或者有新的服務(wù)節(jié)點(diǎn)動(dòng)態(tài)加入埠啃,導(dǎo)致服務(wù)節(jié)點(diǎn)數(shù)發(fā)生變化死宣,靜態(tài)分配的QPS需要實(shí)時(shí)動(dòng)態(tài)調(diào)整,否則會(huì)導(dǎo)致流控不準(zhǔn)霸妹。
分布式服務(wù)框架的一個(gè)特點(diǎn)就是服務(wù)的動(dòng)態(tài)上下線或自動(dòng)發(fā)現(xiàn)機(jī)制十电,這就決定了在運(yùn)行期服務(wù)節(jié)點(diǎn)數(shù)會(huì)隨著業(yè)務(wù)量的變化而頻發(fā)發(fā)生變化知押,在這種情境下靜態(tài)分配方案顯然無法滿足需求叹螟。
當(dāng)應(yīng)用和服務(wù)遷移到云上之后PaaS平臺(tái)的一個(gè)重要功能就是支持應(yīng)用和服務(wù)的彈性伸縮鹃骂,在云上,資源都是動(dòng)態(tài)分配和調(diào)整的罢绽,靜態(tài)分配閾值方案無法適應(yīng)服務(wù)遷移到云上畏线。
1.3 動(dòng)態(tài)配額分配制
為了解決靜態(tài)分配的缺陷,在實(shí)踐中通常會(huì)采用動(dòng)態(tài)配額分配制良价。它的工作原理:由服務(wù)注冊(cè)中心以流控周期T為單位寝殴,動(dòng)態(tài)推送每個(gè)節(jié)點(diǎn)分配的流控閾值QPS。當(dāng)服務(wù)節(jié)點(diǎn)發(fā)生變化時(shí)明垢,會(huì)觸發(fā)服務(wù)注冊(cè)中心重新計(jì)算每個(gè)節(jié)點(diǎn)的配額蚣常,然后進(jìn)行推送,這樣無論是新增還是減少服務(wù)節(jié)點(diǎn)數(shù)痊银,都能夠在下一個(gè)流控周期內(nèi)被識(shí)別和處理抵蚊,這就解決了傳統(tǒng)靜態(tài)分配方案無法適應(yīng)節(jié)點(diǎn)數(shù)動(dòng)態(tài)變化的問題。
在生產(chǎn)環(huán)境中溯革,每臺(tái)機(jī)器/VM的配置可能不同贞绳,如果每個(gè)服務(wù)節(jié)點(diǎn)采用流控總閾值/服務(wù)節(jié)點(diǎn)數(shù)這種平均主義,可能會(huì)發(fā)生性能高致稀、處理快的節(jié)點(diǎn)配額很快用完冈闭,但是性能差的節(jié)點(diǎn)配額有剩余的情況,這會(huì)導(dǎo)致總的配額沒用完抖单,但是系統(tǒng)卻發(fā)生了靜態(tài)流控的問題萎攒。一種解決方案就是服務(wù)注冊(cè)中心在做配額計(jì)算時(shí),根據(jù)各個(gè)服務(wù)節(jié)點(diǎn)的性能KPI數(shù)據(jù)(例如服務(wù)調(diào)用平均延遲)做加權(quán)矛绘,處理能力差的服務(wù)節(jié)點(diǎn)分配的指標(biāo)少些躺酒,性能高的分配的指標(biāo)多些,這樣就能夠盡可能低地降低流控偏差蔑歌。
還有另外一種解決方案就是配額指標(biāo)返回和重新申請(qǐng)羹应,每個(gè)服務(wù)節(jié)點(diǎn)根據(jù)自身分配的指標(biāo)值、處理速率做預(yù)測(cè)次屠,如果計(jì)算結(jié)果表明指標(biāo)會(huì)有剩余园匹,則把多余的返還服務(wù)注冊(cè)中心;對(duì)于配額已經(jīng)使用完的服務(wù)節(jié)點(diǎn)劫灶,重新主動(dòng)去服務(wù)注冊(cè)中心申請(qǐng)配額裸违,如果連續(xù)N次都申請(qǐng)不到新的配額指標(biāo),則對(duì)于新接入的請(qǐng)求消息做流控本昏。
最后一點(diǎn)就是結(jié)合負(fù)載均衡進(jìn)行靜態(tài)流控供汛,才能夠?qū)崿F(xiàn)更精確的調(diào)度和控制。消費(fèi)者根據(jù)各服務(wù)節(jié)點(diǎn)的負(fù)載情況做加權(quán)路由,性能差的節(jié)點(diǎn)路由到的消息更少怔昨,由于配額計(jì)算也根據(jù)負(fù)載做了加權(quán)調(diào)整雀久,最終分配給性能差的節(jié)點(diǎn)配額指標(biāo)也較少,這樣既保證了系統(tǒng)的負(fù)載均衡趁舀,有實(shí)現(xiàn)了配額的更合理分配赖捌。
1.4 動(dòng)態(tài)配額申請(qǐng)制
盡管動(dòng)態(tài)配額分配制可以解決節(jié)點(diǎn)變化引起的流控不準(zhǔn)問題,也能夠改善平均主義配額分配導(dǎo)致的貧富不均矮烹,但是它并不是最優(yōu)的方案越庇,它的缺點(diǎn)總結(jié)如下:
- 如果流控周期T比較大,各個(gè)服務(wù)節(jié)點(diǎn)的負(fù)載情況變化比較快奉狈,服務(wù)節(jié)點(diǎn)的負(fù)載反饋到注冊(cè)中心卤唉,由注冊(cè)中心統(tǒng)一計(jì)算之后再做配額均衡,誤差會(huì)比較大仁期。
- 如果流控周期T比較小搬味,服務(wù)注冊(cè)中心需要實(shí)時(shí)獲取各個(gè)服務(wù)節(jié)點(diǎn)的性能KPI數(shù)據(jù)并計(jì)算負(fù)載情況,經(jīng)過性能數(shù)據(jù)采集蟀拷、上報(bào)碰纬、匯總和計(jì)算之后,會(huì)有一定的時(shí)延问芬,這會(huì)導(dǎo)致流控滯后產(chǎn)生誤差悦析。
- 如果采用配額返還和重新申請(qǐng)方式,則會(huì)增加交互次數(shù)此衅,同時(shí)也會(huì)存在時(shí)序誤差强戴,效果有限。
- 擴(kuò)展性差挡鞍,負(fù)載的匯總骑歹、計(jì)算和配額分配、下發(fā)都由服務(wù)注冊(cè)中心完成墨微,如果服務(wù)注冊(cè)中心管理的節(jié)點(diǎn)數(shù)非常多道媚,則服務(wù)注冊(cè)中心的計(jì)算壓力就非常大了,隨著服務(wù)節(jié)點(diǎn)數(shù)的增加服務(wù)注冊(cè)中心的配額申請(qǐng)效率會(huì)急速下降翘县,系統(tǒng)不具備平滑擴(kuò)展能力最域。
要解決上述問題,可以采用動(dòng)態(tài)配額申請(qǐng)制锈麸,它的工作原理如下: - 系統(tǒng)部署的時(shí)候镀脂,根據(jù)服務(wù)節(jié)點(diǎn)數(shù)和靜態(tài)流控QPS閾值,拿出一定比例的配額做初始分配忘伞,剩余的配額放在配額資源池中薄翅。
- 哪個(gè)服務(wù)節(jié)點(diǎn)使用完了配額沙兰,就主動(dòng)向服務(wù)注冊(cè)中心申請(qǐng)配額。配額的申請(qǐng)策略是翘魄,如果流控周期為T鼎天,則將周期T分成更小的周期T/N(N為經(jīng)驗(yàn)值,默認(rèn)值為10)熟丸,當(dāng)前的服務(wù)節(jié)點(diǎn)數(shù)為M個(gè),則申請(qǐng)的配額為(總QPS配額-已分配的QPS配額)/M*T/N伪节。
- 總的配額如果申請(qǐng)完光羞,則返回0配額給各個(gè)申請(qǐng)配額的服務(wù)節(jié)點(diǎn),服務(wù)節(jié)點(diǎn)對(duì)新接入的請(qǐng)求消息進(jìn)行流控怀大。
動(dòng)態(tài)配額申請(qǐng)制的優(yōu)點(diǎn): - 各個(gè)服務(wù)節(jié)點(diǎn)最清楚自己的負(fù)載情況纱兑,性能KPI數(shù)據(jù)在本地內(nèi)存中計(jì)算獲得,實(shí)時(shí)性高化借。
- 由各個(gè)服務(wù)節(jié)點(diǎn)根據(jù)自身負(fù)載情況去申請(qǐng)配額潜慎,保證性能高的節(jié)點(diǎn)有更高的配額,性能差的自然配額就少蓖康,這樣能夠更合理地配額資源铐炫,實(shí)現(xiàn)流控的精確性。
實(shí)踐經(jīng)驗(yàn)表明蒜焊,采用動(dòng)態(tài)配額申請(qǐng)制的靜態(tài)流控更精確倒信,在實(shí)戰(zhàn)中效果也更好。
2. 動(dòng)態(tài)流控
動(dòng)態(tài)流控的最終目標(biāo)是為了保命泳梆,并不是對(duì)流量或者訪問速度做精確控制鳖悠。當(dāng)系統(tǒng)負(fù)載壓力非常大時(shí),系統(tǒng)進(jìn)入過負(fù)載狀態(tài)优妙,可能是CPU乘综、內(nèi)存資源已經(jīng)過載,也可能是應(yīng)用進(jìn)程內(nèi)部的資源幾乎耗盡套硼,如果繼續(xù)全量處理業(yè)務(wù)卡辰,可能會(huì)導(dǎo)致長(zhǎng)時(shí)間的Full GC、消息嚴(yán)重積壓或者應(yīng)用進(jìn)程宕機(jī)邪意,最終將壓力轉(zhuǎn)移到集群其他節(jié)點(diǎn)看政,引起級(jí)聯(lián)故障。
觸發(fā)動(dòng)態(tài)流控的因子是資源抄罕,資源又分為系統(tǒng)資源和應(yīng)用資源兩大類允蚣,根據(jù)不同的資源負(fù)載情況,動(dòng)態(tài)流控又分為多個(gè)級(jí)別呆贿,每個(gè)級(jí)別流控系統(tǒng)都不同嚷兔,也就是被拒絕掉的消息比例不同森渐。每個(gè)級(jí)別都有相應(yīng)的流控閾值,這個(gè)閾值通常支持在線動(dòng)態(tài)調(diào)整冒晰。
2.1 動(dòng)態(tài)流控因子
動(dòng)態(tài)流控因子包括系統(tǒng)資源和應(yīng)用資源兩大類同衣,常用的系統(tǒng)資源包括:
- 應(yīng)用進(jìn)程所在主機(jī)/VM的CPU使用率。
- 應(yīng)用進(jìn)程所在主機(jī)/VM的內(nèi)存使用率壶运。
主機(jī)CPU耐齐、內(nèi)存使用率采集算法非常多,例如使用java.lang.Process執(zhí)行top蒋情、sar等外部命令獲取系統(tǒng)資源使用情況埠况,然后解析后計(jì)算獲得資源使用率。也可以直接讀取操作系統(tǒng)的系統(tǒng)文件獲取相關(guān)數(shù)據(jù)棵癣,需要注意的是辕翰,無論是執(zhí)行操作系統(tǒng)的本地命令,還是直接讀取操作系統(tǒng)的資源使用率文件狈谊,都是操作系統(tǒng)本地相關(guān)的喜命,不同的操作系統(tǒng)和服務(wù)器,命令和輸出格式可能存在很大差異河劝。在計(jì)算時(shí)需要首先判斷操作系統(tǒng)類型壁榕,然后調(diào)用相關(guān)操作系統(tǒng)的資源采集接口實(shí)現(xiàn)類,通過這種方式就可以支持跨平臺(tái)赎瞎。
常用的應(yīng)用資源包括: - JVM堆內(nèi)存使用率护桦。
- 消息隊(duì)列積壓率。
- 會(huì)話積壓率(可選)煎娇。
具體實(shí)現(xiàn)策略是系統(tǒng)啟動(dòng)時(shí)拉起一個(gè)管理線程二庵,定時(shí)采集應(yīng)用資源的使用率,并刷新動(dòng)態(tài)流控的應(yīng)用資源閾值缓呛。
2.2 分級(jí)流控
通常催享,動(dòng)態(tài)流控是分級(jí)別的,不同級(jí)別拒掉的消息比例不同哟绊,這取決于資源的負(fù)載使用情況因妙。例如當(dāng)發(fā)生一級(jí)流控時(shí),拒絕掉1/8的消息票髓;發(fā)生二級(jí)流控時(shí)攀涵,拒絕掉1/4的消息。
不同的級(jí)別有不同的流控閾值洽沟,系統(tǒng)上線后提供默認(rèn)的流控閾值以故,不同流控因子的流控閾值不同,業(yè)務(wù)上線之后通常會(huì)根據(jù)現(xiàn)場(chǎng)的實(shí)際情況做閾值調(diào)優(yōu)裆操,因此流控閾值需要支持在線修改和動(dòng)態(tài)生效怒详。
需要指出的是為了防止系統(tǒng)波動(dòng)導(dǎo)致的偶發(fā)性流控炉媒,無論是進(jìn)入流控狀態(tài)還是從流控狀態(tài)恢復(fù),都需要連續(xù)采集N次并計(jì)算平均值昆烁,如果連續(xù)N次平均值大于流控閾值吊骤,則進(jìn)入流控狀態(tài);同理静尼,只有連續(xù)N次資源使用率平均值低于流控閾值白粉,才能脫離流控狀態(tài)恢復(fù)正常。
根據(jù)資源使用率的變化鼠渺,流控會(huì)發(fā)生升級(jí)或者降級(jí)鸭巴,在同一個(gè)流控周期內(nèi),不會(huì)發(fā)生流控級(jí)別的跳變系冗。
3. 并發(fā)控制
并發(fā)控制針對(duì)線程的并發(fā)執(zhí)行數(shù)進(jìn)行控制奕扣,它的本質(zhì)是限制對(duì)某個(gè)服務(wù)或者服務(wù)的方法過渡消費(fèi)薪鹦,耗用過多的資源而影響其他服務(wù)的正常運(yùn)行掌敬。
并發(fā)控制有兩種形式:
- 針對(duì)服務(wù)提供者的全局控制。
- 針對(duì)服務(wù)消費(fèi)者的局部控制池磁。
4. 連接控制
通常分布式服務(wù)框架服務(wù)提供者和消費(fèi)者之間采用長(zhǎng)連接私有協(xié)議奔害,為了防止因?yàn)橄M(fèi)者連接數(shù)過多導(dǎo)致服務(wù)端負(fù)載壓力過大,系統(tǒng)需要支持針對(duì)連接數(shù)進(jìn)行控制地熄。
5. 并發(fā)和連接控制算法
基于服務(wù)調(diào)用Pipeline機(jī)制华临,可以對(duì)請(qǐng)求消息接收和發(fā)送、應(yīng)答消息接收和發(fā)送端考、異常消息等切面攔截(類似Sprint的AOP機(jī)制雅潭,但是沒采用反射機(jī)制,性能更高)却特,利用Pipeline攔截切面接口扶供,對(duì)請(qǐng)求消息做服務(wù)調(diào)用前的攔截和計(jì)數(shù),根據(jù)計(jì)數(shù)器做流控裂明,服務(wù)端的算法如下:
- 獲取流控閾值椿浓。
- 從全局RPC上下文中獲取當(dāng)前的并發(fā)執(zhí)行數(shù),與流控閾值對(duì)比闽晦,如果小于流控閾值扳碍,則對(duì)當(dāng)前的計(jì)數(shù)器做原子自增。
- 如果等于或者大于流控閾值仙蛉,則拋出RPC流控異常給客戶端笋敞。
- 服務(wù)調(diào)用執(zhí)行完成之后,獲取RPC上下文中的并發(fā)執(zhí)行數(shù)荠瘪,做原子自減液样。
客戶端的流控算法與服務(wù)端的不太一樣振亮,客戶端的流控目的就是要降低對(duì)服務(wù)端的沖擊,因此當(dāng)客戶端達(dá)到流控閾值之后鞭莽,需要將當(dāng)前的線程掛起坊秸,等待其他線程執(zhí)行完畢后再執(zhí)行,或者超時(shí)澎怒,它的算法如下: - 獲取流控閾值褒搔。
- 從全局RPC上下文中獲取當(dāng)前的并發(fā)執(zhí)行數(shù),與流控閾值對(duì)比喷面,如果小于流控閾值星瘾,則對(duì)當(dāng)前的計(jì)數(shù)器做原子自增。
- 如果等于或者大于流控閾值惧辈,當(dāng)前線程進(jìn)入wait狀態(tài)琳状,wait超時(shí)時(shí)間為服務(wù)調(diào)用的超時(shí)時(shí)間。
- 如果有其他線程服務(wù)調(diào)用完成盒齿,調(diào)用計(jì)數(shù)器自減念逞,則并發(fā)執(zhí)行數(shù)大于閾值,線程被notify边翁,則退出wait翎承,繼續(xù)執(zhí)行。
6. 總結(jié)
流量控制是保障服務(wù)SLA的重要措施符匾,也是業(yè)務(wù)高峰期故障預(yù)防和恢復(fù)的有效手段叨咖,分布式服務(wù)框架需要支持不同的流控策略,還要支持流控閾值啊胶、策略的在線調(diào)整甸各,不需要重啟應(yīng)用即可動(dòng)態(tài)生效,提升線上服務(wù)治理的效率和敏捷性焰坪。