限流系統(tǒng)是對(duì)資源調(diào)用的控制組件,主要涵蓋授權(quán)、限流、降級(jí)、調(diào)用統(tǒng)計(jì)等功能模塊。限流系統(tǒng)有兩個(gè)基礎(chǔ)概念:資源和策略,對(duì)特定的資源采取不同的控制策略,起到保障應(yīng)用穩(wěn)定性的作用。限流系統(tǒng)提供了多個(gè)默認(rèn)切入點(diǎn)覆蓋了大部分使用場景,保證對(duì)應(yīng)用的低侵入性;同時(shí)也支持硬編碼或者自定義aop的方式來支持特定的使用需求。限流系統(tǒng)提供了全面的運(yùn)行狀態(tài)監(jiān)控,實(shí)時(shí)監(jiān)控資源的調(diào)用情況(qps、rt、限流降級(jí)等信息)。
如何利用限流系統(tǒng)的特性,來統(tǒng)計(jì)熱點(diǎn)呢?在這里,我們主要介紹一下,限流系統(tǒng)是如何來判斷熱點(diǎn)的,它的工作原理是什么,它的性能如何;它目前已經(jīng)在哪些場景里面使用。
1. 熱點(diǎn)的特性
a) 海量的統(tǒng)計(jì)基數(shù)
可能的熱點(diǎn)分為兩種,一種是事前已知的(例如營銷人員的已經(jīng)整理出秒殺商品的列表),另外一種是突發(fā)的,不可以預(yù)計(jì)的(例如被刷單的商品,或者是黑馬產(chǎn)品)。對(duì)于前面一種,只需要計(jì)算這些已知的列表即可,但是對(duì)于后者,由于基數(shù)是海量的,舉個(gè)例子,如果有一個(gè)方法,它傳入的參數(shù)是商品id, 這個(gè)商品的id以淘寶的規(guī)模來說,是上億的。如果把所有的商品id都記錄統(tǒng)計(jì)起來,再進(jìn)行排序,統(tǒng)計(jì)出熱點(diǎn),這對(duì)于實(shí)時(shí)的工具來說,是不可行的。所以為了解決熱點(diǎn)統(tǒng)計(jì),我們必須找到一個(gè)好的數(shù)據(jù)結(jié)構(gòu),這個(gè)結(jié)構(gòu)能夠僅保存常常被訪問的一定數(shù)量商品id,并且可以控制結(jié)構(gòu)的大小,統(tǒng)計(jì)量。這是非常重要的一個(gè)步驟。
b) 統(tǒng)計(jì)熱點(diǎn)的單位時(shí)間的維度。
這里有一個(gè)必須強(qiáng)調(diào)的概念: 單位時(shí)間而不是總訪問量。 打個(gè)比方,一個(gè)商品,在一小時(shí)以內(nèi)被訪問了3600次,但是它很均勻的每秒被訪問一次,那么這個(gè)商品可能在系統(tǒng)的承受范圍之內(nèi),并會(huì)對(duì)系統(tǒng)帶來損傷;而另外一個(gè)商品,它一小時(shí)被訪問了60次,但都落在同一秒,那么這個(gè)商品可能就是一個(gè)熱點(diǎn)商品。對(duì)于”單位時(shí)間”的定義,是決策一個(gè)參數(shù)是否成為熱點(diǎn)的一個(gè)重要的因素;如果太粗,必然會(huì)帶來毛刺,導(dǎo)致系統(tǒng)性能不平滑;如果太細(xì),會(huì)給性能帶來挑戰(zhàn)
c) 在分布式系統(tǒng)給統(tǒng)計(jì)帶來的挑戰(zhàn)
熱點(diǎn)的統(tǒng)計(jì)范圍可能是單機(jī),也可能是集群。如何能快速的在集群中統(tǒng)計(jì),并且讓限流規(guī)則在單機(jī)上生效,是非常重要的。
2. 如何解決上述問題
2.1 首先,找到一個(gè)可行的數(shù)據(jù)結(jié)構(gòu)
這個(gè)結(jié)構(gòu)必須滿足訪問修改快速,并發(fā)性好,占用內(nèi)存空間少,存儲(chǔ)的個(gè)數(shù)大小可控制,并且可以驅(qū)逐訪問量少的entry,從而可以達(dá)到實(shí)時(shí)統(tǒng)計(jì)熱點(diǎn)的查詢數(shù)字。
其實(shí),業(yè)界有一個(gè)現(xiàn)成的好結(jié)構(gòu)。它就是團(tuán)隊(duì)用于guava里的ConcurrentLinkedHashMap (http://code..com/p/concurrentlinkedhashmap)。它有下面幾個(gè)特點(diǎn):
2.1.a 支持并發(fā)。它是實(shí)現(xiàn)了ConcurrentMap接口的。基本上它的實(shí)現(xiàn)是遵循concurrentMap的思想的。這里就不多贅述。
2.1.b 它把我們普通concurrenthashmap的segments用一個(gè)額外的雙鏈表維護(hù)起來,通過操作這個(gè)鏈表,里面的entry可以在O(1)的時(shí)間之類刪除或者重新排序。當(dāng)一個(gè)entry被訪問,則被移動(dòng)到表頭;當(dāng)這個(gè)map的容量超過預(yù)設(shè),則移除位于鏈表尾的entry。這樣就可以保證表頭是新被使用的entry,表尾是近少被使用的entry
2.1.c 從另外一個(gè)角度來說,可以把ConcurrentLinkedHashMap 分成兩個(gè)view. 一個(gè)是同步的,一個(gè)是異步的。Hashtable對(duì)于調(diào)用方來說是同步的,鏈表對(duì)于調(diào)用方式不透明的,異步的。
2.1.d 性能和concurrenthashmap的比較, 肯定比concurrenthashmap差,但是屬于可以忍受的范圍。下面是官方給出的數(shù)據(jù)
綜上所述,我們可以利用這個(gè)LRU concurrent map link,保證我們?cè)趩挝粫r(shí)間內(nèi),僅保存有限數(shù)量訪問量較高的key, 近比較少訪問的key,我們則可以認(rèn)為它不是熱點(diǎn),當(dāng)map的Size達(dá)到上限之后,清除這個(gè)key
2.2 統(tǒng)計(jì)單位時(shí)間的維度
現(xiàn)在我們來看第二個(gè)問題,如何統(tǒng)計(jì)單位時(shí)間的key的qps. 其實(shí)這個(gè)正是限流系統(tǒng)的拿手好戲,用動(dòng)態(tài)滑動(dòng)窗口平滑的統(tǒng)計(jì)qps.
簡單的說,限流系統(tǒng)為每個(gè)簇點(diǎn)(可以簡單的理解為需要統(tǒng)計(jì)的方法),做了一個(gè)滑動(dòng)窗口。更具體的說,即限流系統(tǒng)把采樣窗口長度設(shè)為2秒,這個(gè)采樣窗口又被分割為20個(gè)格子。通過用一定的算法來統(tǒng)計(jì)這20個(gè)格子的平均滑動(dòng)窗口累積平均值來進(jìn)行決策。
為什么采用平均滑動(dòng)窗口累計(jì)平均值是為了削平毛刺qps(在某個(gè)點(diǎn)突發(fā)的qps)對(duì)整體的影響。該公式如下:

更具體的說明在: http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average 可以查到。
說到這里,聰明的讀者應(yīng)該早就猜到了,限流系統(tǒng)通過把兩個(gè)利器結(jié)合起來,即滑動(dòng)窗口和 concurrent link hashmap,可以統(tǒng)計(jì)在固定的時(shí)間,常常使用的參數(shù)的值。
限流系統(tǒng)數(shù)據(jù)結(jié)構(gòu)如下所示:
具體的代碼在: http://gitlab.alibaba-inc.com/middleware-asp/限流系統(tǒng) 歡迎大家來指正
2.3 如何解決集群的挑戰(zhàn)
2.3.1 幸運(yùn)的是,限流系統(tǒng)天生自帶獲取簇點(diǎn)qps的功能
使用過限流系統(tǒng)的人都會(huì)發(fā)現(xiàn),8719這個(gè)端口是被限流系統(tǒng)占用了的。通過這個(gè)端口,我們可以用獲取到簇點(diǎn)的qps統(tǒng)計(jì)信息。有了這個(gè)“后門”,我們就可以輕松快速的獲取到qps的信息了
2.3.2 如何在大集群里匯總這些qps的信息
接下來要解決的問題就是,如何在上千臺(tái)機(jī)器里面快速匯總這些信息。還好之前我們?cè)谧?.0.7的集群統(tǒng)計(jì)的時(shí)候,有了一定的經(jīng)驗(yàn)。 這個(gè)算法后來也用在了預(yù)案分配巨大的url task中。簡單的說,就是用一個(gè)隊(duì)列來放任務(wù),多個(gè)線程來執(zhí)行任務(wù),一個(gè)線程來merge取回的結(jié)果。通過使用這個(gè)方法,一個(gè)比較大的集群,例如buy等,2秒可以返回統(tǒng)計(jì)結(jié)果。
有了集群的總體匯總信息之后,我們?cè)賹⑦@個(gè)信息利用diamond來推廣到具體的機(jī)器上去。這樣的延遲大概是2-3s左右。
3 總結(jié)以及限流系統(tǒng)性能報(bào)告:
簡單的說,存放一個(gè)這樣的結(jié)構(gòu),大概大小是8k. 它的默認(rèn)參數(shù)是每個(gè)簇點(diǎn)的存放2s的滑動(dòng)窗口,20個(gè)格子,每個(gè)格子多可以保存200個(gè)參數(shù),那么在壞的情況下,這個(gè)結(jié)構(gòu)的大小將會(huì)是8k+4000個(gè)參數(shù)大小。
吞吐量在我的日常機(jī)器上是29W,在生產(chǎn)機(jī)上應(yīng)該會(huì)更好。
本站文章版權(quán)歸原作者及原出處所有 。內(nèi)容為作者個(gè)人觀點(diǎn), 并不代表本站贊同其觀點(diǎn)和對(duì)其真實(shí)性負(fù)責(zé),本站只提供參考并不構(gòu)成任何投資及應(yīng)用建議。本站是一個(gè)個(gè)人學(xué)習(xí)交流的平臺(tái),網(wǎng)站上部分文章為轉(zhuǎn)載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對(duì)作者和來源進(jìn)行了通告,但是能力有限或疏忽,造成漏登,請(qǐng)及時(shí)聯(lián)系我們,我們將根據(jù)著作權(quán)人的要求,立即更正或者刪除有關(guān)內(nèi)容。本站擁有對(duì)此聲明的最終解釋權(quán)。