限流系統是對資源調用的控制組件,主要涵蓋授權、限流、降級、調用統計等功能模塊。限流系統有兩個基礎概念:資源和策略,對特定的資源採取不同的控制策略,起到保障應用穩定性的作用。限流系統提供了多個默認切入點覆蓋了大部分使用場景,保證對應用的低侵入性;同時也支持硬編碼或者自定義aop的方式來支持特定的使用需求。限流系統提供了全面的運行狀態監控,實時監控資源的調用情況(qps、rt、限流降級等信息)。
如何利用限流系統的特性,來統計熱點呢?在這裏,我們主要介紹一下,限流系統是如何來判斷熱點的,它的工作原理是什麼,它的性能如何;它目前已經在哪些場景裏面使用。
1. 熱點的特性
a) 海量的統計基數
可能的熱點分爲兩種,一種是事前已知的(例如營銷人員的已經整理出秒殺商品的列表),另外一種是突發的,不可以預計的(例如被刷單的商品,或者是黑馬產品)。對於前面一種,只需要計算這些已知的列表即可,但是對於後者,由於基數是海量的,舉個例子,如果有一個方法,它傳入的參數是商品id, 這個商品的id以淘寶的規模來說,是上億的。如果把所有的商品id都記錄統計起來,再進行排序,統計出熱點,這對於實時的工具來說,是不可行的。所以爲了解決熱點統計,我們必須找到一個好的數據結構,這個結構能夠僅保存最常常被訪問的一定數量商品id,並且可以控制結構的大小,統計量。這是非常重要的一個步驟。
b) 統計熱點的單位時間的維度
這裏有一個必須強調的概念: 單位時間而不是總訪問量。 打個比方,一個商品,在一小時以內被訪問了3600次,但是它很均勻的每秒被訪問一次,那麼這個商品可能在系統的承受範圍之內,並會對系統帶來損傷;而另外一個商品,它一小時被訪問了60次,但都落在同一秒,那麼這個商品可能就是一個熱點商品。對於”單位時間”的定義,是決策一個參數是否成爲熱點的一個重要的因素;如果太粗,必然會帶來毛刺,導致系統性能不平滑;如果太細,會給性能帶來挑戰。
c) 在分佈式系統給統計帶來的挑戰
熱點的統計範圍可能是單機,也可能是集羣。如何能快速的在集羣中統計,並且讓限流規則在單機上生效,是非常重要的。
2. 如何解決上述問題
2.1 首先,找到一個可行的數據結構
這個結構必須滿足訪問修改快速,併發性好,佔用內存空間少,存儲的個數大小可控制,並且可以驅逐訪問量少的entry,從而可以達到實時統計熱點的查詢數字。
其實,業界有一個現成的好結構。它就是google團隊用於guava裏的ConcurrentLinkedHashMap (http://code.google.com/p/concurrentlinkedhashmap)。
2.1.a 支持併發。它是實現了ConcurrentMap接口的。基本上它的實現是遵循concurrentMap的思想的。這裏就不多贅述。
2.1.b 它把我們普通concurrenthashmap的segments用一個額外的雙鏈表維護起來,通過操作這個鏈表,裏面的entry可以在O(1)的時間之類刪除或者重新排序。當一個entry被訪問,則被移動到表頭;當這個map的容量超過預設,則移除位於鏈表尾的entry。這樣就可以保證表頭是最新被使用的entry,表尾是最近最少被使用的entry
2.1.c 從另外一個角度來說,可以把ConcurrentLinkedHashMap 分成兩個view. 一個是同步的,一個是異步的。Hashtable對於調用方來說是同步的,鏈表對於調用方式不透明的,異步的。
2.1.d 性能和concurrenthashmap的比較, 肯定比concurrenthashmap差,但是屬於可以忍受的範圍。下面是官方給出的數據
綜上所述,我們可以利用這個LRU concurrent map link,保證我們在單位時間內,僅保存有限數量訪問量較高的key, 最近比較少訪問的key,我們則可以認爲它不是熱點,當map的Size達到上限之後,清除這個key
2.2 統計單位時間的維度
現在我們來看第二個問題,如何統計單位時間的key的qps. 其實這個正是限流系統的拿手好戲,用動態滑動窗口平滑的統計qps.
簡單的說,限流系統爲每個簇點(可以簡單的理解爲需要統計的方法),做了一個滑動窗口。更具體的說,即限流系統把採樣窗口長度設爲2秒,這個採樣窗口又被分割爲20個格子。通過用一定的算法來統計這20個格子的平均滑動窗口累積平均值來進行決策。
爲什麼採用平均滑動窗口累計平均值是爲了削平毛刺qps(在某個點突發的qps)對整體的影響。該公式如下:
更具體的說明在:
http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
可以查到。
說到這裏,聰明的讀者應該早就猜到了,限流系統通過把兩個利器結合起來,即滑動窗口和google concurrent link hashmap,可以統計在固定的時間,最常常使用的參數的值。
限流系統數據結構如下所示:
具體的代碼在: http://gitlab.alibaba-inc.com/middleware-asp/限流系統 歡迎大家來指正
2.3 如何解決集羣的挑戰
2.3.1 幸運的是,限流系統天生自帶獲取簇點qps的功能
使用過限流系統的人都會發現,8719這個端口是被限流系統佔用了的。通過這個端口,我們可以用獲取到簇點的qps統計信息。有了這個“後門”,我們就可以輕鬆快速的獲取到qps的信息了
2.3.2 如何在大集羣裏彙總這些qps的信息
接下來要解決的問題就是,如何在上千臺機器裏面快速彙總這些信息。還好之前我們在做2.0.7的集羣統計的時候,有了一定的經驗。 這個算法後來也用在了預案分配巨大的url task中。簡單的說,就是用一個隊列來放任務,多個線程來執行任務,一個線程來merge取回的結果。通過使用這個方法,一個比較大的集羣,例如buy等,2秒可以返回統計結果。
有了集羣的總體彙總信息之後,我們再將這個信息利用diamond來推廣到具體的機器上去。這樣的延遲大概是2-3s左右。
3 總結以及限流系統性能報告:
簡單的說,存放一個這樣的結構,大概大小是8k. 它的默認參數是每個簇點的存放2s的滑動窗口,20個格子,每個格子最多可以保存200個參數,那麼在最壞的情況下,這個結構的大小將會是8k+4000個參數大小。
吞吐量在我的日常機器上是29W,在生產機上應該會更好。