天天P圖-分散式頻控系統的設計和優化
為什麼要做分散式頻控系統?
相信之前刷屏的「八一軍裝照」和「小學生證件照」大家都不陌生。類似這樣的運營活動突然湧入的巨大流量對天天P圖後台造成的衝擊不可小覷。就拿軍裝照來說,短短三小時,後台請求量就由10W/min突發到110W/min,短時間內無法調集足夠多的機器來應對這些突發的流量,所以一套智能的分散式頻控系統就非常有必要了。另外,隨著天天P圖人臉融合這一極具創意的技術知名度越來越高,也越來越多的第三方想和我們進行合作,使用我們的人臉融合能力。針對不同的第三方給予不同容量的後台處理能力也是很有必要的。綜上,分散式頻控系統的設計和開發提上日程。
圖1 八一軍裝照
頻控系統可用來對流量的削峰管理,使進入後台的流量盡在掌控之中,對後台的過載和雪崩防護可謂意義重大。它還可以對使用同一個介面的不同用戶進行不同的頻控額度管理,提供差異化服務。
當前廠內廠外很多業務都使用單機頻控。單機頻控只能做簡單的流量攔截,簡單而又粗暴,不考慮集群中各機器性能的差異性,不考慮邏輯系統的真實容量及容量可變性,進行簡單的設置和攔截。要想全局頻控和智能頻控,還是得自己做一套!
頻控策略的設計
根據一些現有方案的研究,我大致把頻控策略分為以下幾類:
圖2 幾種頻控策略的對比
即時消費即時結算模式
該模式的原理是,接入層每收到一個請求都去頻控中心進行頻控校驗,如果超限,進行攔截,如果未超限,請求放行,進行下一步的業務邏輯處理。
該方案有其優點,實現簡單,頻控實時性好。
但該方案對業務是阻塞的,而且性能低,每一次請求都需要訪問頻控中心,進行存儲讀寫。該方案不具有接入層的抗流能力,即頻控中心壓力會隨著接入層湧入請求量同比例放大。
預付費模式
該模式原理是,間隔一段時間去頻控中心拉取一定流量額度,等這些額度消耗完了再去頻控中心拉取下一批額度。根據有無額度,決定是否攔截。
該方案較第一種方案性能大幅提升,並具有極高的抗流能力。因為該模式不需要每次訪問頻控中心。
但該方案額度難以較好分配。一種分配方案是根據接入機數量,進行平均分配。這種方案沒法考慮機器性能的差異,並且機器數並不是一成不變的,不具有良好的擴展性,而且如有機器出現故障,會影響整體的頻控準確性。
先消費再結算模式
該模式是在前兩種模式的基礎上進行優化改進創造而來。
原理是,先放行一定數量的請求,然後批量上報到頻控中心進行校驗。根據校驗結果,來決定接下來的請求是否攔截。
該模式是一種非同步批量上報模式,對業務來說非阻塞,具有極高的性能和抗流能力。只是實時性稍差一點。但頻控系統作為業務系統的輔助系統,該方案相對於其他優點來說,實時性稍差可以接受。故頻控系統採用該種方案。
頻控系統完整結構
如下圖所示,頻控系統分agent(FcAgent)和頻控中心server(FcSvr)兩塊。agent和業務CGI部署在同一機器中,頻控server負責進行頻控的校驗。
圖3 頻控系統架構圖
共享內存kv用來存儲各介面的頻控結果,共享內存隊列用來存放通過的請求記錄。請求進入CGI後,只需要讀取共享內存中該介面的頻控結果,即可決定對該請求是否通行或者攔截。如果通行,向共享內存隊列插入一條通行記錄,再進行接下來其他的業務邏輯處理。FcAgent負責從共享內存隊列中提取通行記錄,累積到一定量後,向FcSvr進行上報檢驗是否頻控超限,將獲取的結果寫回到共享內存kv中供下一次請求校驗使用。
頻控的配置信息存儲在Redis中,使用運營系統進行頻控額度等配置信息的更新。
頻控計算方法
關於頻控計算方法,業內主要分為計算器法、滑動窗口法、漏桶演算法、令牌桶演算法。計數器法簡單,但是存儲成本較高,而且有邊界問題。
滑動窗口只是在計數器法上面進行精度再切割,降低了邊界問題發生的風險,存儲成本依舊很高。
漏桶演算法原理是設定桶的一個恆定水流出速率,如果請求的流入速率大於桶設置的流出速率,桶自然會溢出,從而頻控超限。漏桶演算法可保證桶的流入速率即請求流入速率不超過設定的某一固定值。令牌桶演算法本質和漏桶演算法類似。只是說是定時向桶里勻速放入令牌,通過桶里是否有令牌來決定是否頻控超限。
圖4 漏桶演算法示意圖
這裡採用基於漏桶演算法的分散式改進演算法進行頻控的校驗計算。
按照傳統漏桶演算法,當請求進來時,需要計算桶當前水量,桶剩餘水量,根據剩餘水量是否溢出來判斷是否超限。隨後更新當前時間戳,桶當前水量,已放行水量。用來進行下次的秒級頻控和總額度頻控。
一次頻控校驗需改寫多個欄位的值,需進行事務性保證。如果加鎖的話,又極大影響了服務的性能。所以這裡採取一次頻控校驗只需INCR更新當前桶水量即可,桶的其它信息(桶重置時間戳、秒級頻控值、桶容量、已放行總量、頻控總額度)進行緩存處理。
根據更新後的桶當前水量值減去這段時間流出的水量,即可知道桶的剩餘水量。桶剩餘水量減去桶容量,即可得桶溢出水量。
這裡採用桶溢出時間這個概念進行頻控攔截依據。桶溢出水量除以秒級頻控值,即為桶溢出時間。桶溢出時間,即表明系統在該段溢出時間內,是不允許放入請求的。將該溢出時間返回給FcAgent,CGI在該溢出時間之後才放行新的請求。
圖5 溢出時間的計算方法
頻控總額度是否超限的判斷依據是緩存中的已放行總量加上當前桶已放行量(桶當前水量-桶初始容量)是否超出總頻控額度。
桶只有在桶配置信息發生變更或者桶長時間未有請求流入時才會進行重置。此時需要刷新桶緩存信息。
該種改進可保證頻控計算的原子化,一次INCR操作即可完成秒級頻控和總額度頻控的校驗。
非同步上報的難點
幾個問題制約著非同步上報時間間隔不能太長也不能太短。
a)頻控延遲問題
非同步上報必然會帶來頻控延遲問題。上報間隔越長延遲越嚴重。所以從這個角度看,上報間隔越小越好。
b)突刺消耗問題
突刺消耗指一個時間周期內,前一段時間就消耗了全部流量,導致後一段時間無流量消耗,請求全部攔截。從這個角度看,上報間隔越小越好。
c)勻速誤限問題
勻速誤限指請求速率不均勻導致被勻速削峰後造成誤限。勻速誤限一般在整體請求速率低於頻控速率而局部請求速率高於頻控速率的情況下發生。從這個角度看,上報間隔越長越好。
圖6 勻速誤限示意圖
d)頻控壓力問題
上報時間間隔越小,對頻控中心壓力越大。從這個角度看,上報間隔越小越好。
綜上幾個問題考慮,上報間隔既不能太小也不能太大。另外,僅僅以時間間隔作為上報依據的話,不管時間間隔設置多小,也難以解決突發高流量情況下,流量瞬間超限的情況。所以這裡採用時間和個數兩個維度,進行非同步上報的依據。
個數維度解決頻控延遲、突刺消耗、頻控壓力、流量突發問題,時間維度解決勻速誤限、請求稀少問題。
那麼,個數維度中的個數該怎麼選定呢?假如全局每秒允許流入1000個請求,有10台接入機,這裡的個數維度就絕對要小於1000/10,即最多累積10個請求就必須進行頻控上報,否則就可能出現超限風險。當然,需要考慮頻控上報到頻控中心的請求延遲,所以要在該個數基礎上進行一定倍數的緩衝,即設定一個緩衝倍數,個數維度即為1000/10/緩衝倍數,以該數值作為個數維度的間隔依據。
個數間隔=頻控值/最大機器數/緩衝倍數
時間間隔= 300ms
圖7 非同步上報時機
高可靠保證:容災與糾錯
a)系統模塊的容災
系統某個模塊出現故障是必須要考慮的情況。在當前分散式頻控系統中,如果頻控中心svr或者存儲系統出現故障怎麼辦?常見的處理策略可能是要麼請求全部放行,要麼請求全部攔截。全部放行有造成衝垮業務服務的風險,全部攔截將會導致全業務不可用,顯然都不是完美的解決方案。
在這裡,可以引入局部頻控策略。那麼,局部頻控的依據是什麼呢?當然是上一次的頻控結果了。在上一次頻控結果的基礎上,進行本地計算當次請求是否超限。
局部溢出時間= max(0,(上次溢出時間 + 請求量/單機秒級頻控量 - (當前時間戳-上次時間戳))
計算出的局部溢出時間如果大於0,表明請求在接下來該段時間內將進行攔截。
b)局部糾錯機制
除了對系統核心模塊的容災策略,多線程高並發下的數據準確問題也是系統高可靠的重要一環。Agent模塊間隔非同步批量頻控校驗避免了同一業務同一時刻發生頻控校驗的情況,然而網路異常情況下仍然可能出現頻控結果逆序到達的情況。加鎖太影響性能,而且發生逆序情況也是低概率事件,所以這裡引入局部糾錯機制,對於逆序到達的頻控結果直接廢棄,避免對頻控準確性造成影響。
那麼,怎麼判斷頻控結果是否逆序到達呢?我們的判斷依據是:同一時刻收到的頻控溢出時間後者必定大於前者。如同時先後收到溢出時間為30ms,20ms,則20ms這次直接剔除。
即如果該次溢出時間小於上次溢出時間減兩次結果時間間隔的值,則認為該次結果為逆序,不予採信。
下圖是採取容災和糾錯策略前後的頻控效果圖。 紅色曲線代表實際請求每秒流入量,藍色曲線代表實際請求每秒放行量。當藍線越趨近於直線,表明頻控準確率越高。
圖8 無容災糾錯頻控效果圖
圖9 有容災糾錯頻控效果圖
從上面兩張效果圖對比可以看出,局部頻控和糾錯解決了頻控質量的波動問題,使得每秒請求放行量基本處於直線水平。
更智能的頻控:動態頻控
當某個調用方調用某個介面流量超過了當初設定的頻控值,是不是就是直接進行攔截呢?我們這邊對不同的調用方給予不同的評級,對於vip調用方(如人民日報),如果請求流量超限的話,會結合當前圖片處理系統的處理能力,進行自動的頻控值上調,達到動態頻控的目的,最大限度地發揮圖片系統的圖片處理能力。
對於非vip的用戶,如果流量超限,對於超限的流量也可以將流量引導到P圖的下載,實現流量變現,降低圖片系統的壓力。
以下為動態頻控流程圖。多級預警、人工擴容和自動擴容相結合、超限流量變現,實現更智能的頻控。
圖10 動態頻控流程圖
極高的頻控性能
a)根據壓測和線上表現,該分散式頻控系統頻控準確率超過99%(某時間段實際放行請求數/某時間段限制放行請求數),局部波動不超過2%(某秒多放行或少放行請求數/每秒頻控值)
b)每個業務每秒只會對頻控中心產生接入機器數*緩衝倍數次請求,故接入層可抵禦百萬級每秒的湧入請求(取決於接入層的系統性能)
c)2台4核8G虛擬機組成的頻控中心系統性能可達10w/s,可支撐約2500個業務的頻控校驗
最後附上線上頻控系統監控圖。藍色代表實際每秒放行請求量,紅色代表實際請求湧入量。藍色基本呈一條直線,表明頻控效果良好。
圖11 頻控效果監控圖
作者簡介:jianghongwu(吳江紅),天天P圖後台開發工程師
文章後記:
天天P圖是由騰訊公司開發的業內領先的圖像處理,相機美拍的APP。歡迎掃碼或搜索關注我們的微信公眾號:「天天P圖攻城獅」,那上面將陸續公開分享我們的技術實踐,期待一起交流學習!
TAG:天天P圖攻城獅 |