訪問頻率限制——窗口相關(guān)算法

上一篇文章講到了利用令牌桶(token bucket)和漏桶(leaky bucket)算法進行訪問頻率限制彤蔽,這些非常通用偿渡,但是也有一些問題颠放,怎么解決(更準確說應(yīng)該是緩解)呢饼酿?

回到最初問題的來源棉圈,其實只要把所有的請求都記錄下來涩堤,每次新來一個請求看最近一段時間有沒有超標即可。然而分瘾,一般并不能這么粗暴的記錄每一條記錄的時間戳胎围,然后統(tǒng)計,因為內(nèi)存可能扛不住德召,CPU可能也扛不住白魂。
于是,有了固定窗口計數(shù)(Fixed Window Counter)這樣的算法上岗。算法做的就是每小段時間用一個值記錄起始時間福荸,另一個值記錄個數(shù)即可。比如肴掷,限制是每1分鐘60次敬锐,那么就在每個整分點(11:11:00)這樣開始計數(shù),每次來請求就增加記錄次數(shù)呆瞻,如果超過60次台夺,就意味著頻率超標了。然后每個這樣的記錄的過期時間是1分鐘痴脾,這樣颤介,如果一個用戶訪問幾次之后,不再訪問,內(nèi)存中對應(yīng)的記錄值也會清掉滚朵。事實上Github好多實現(xiàn)就是用了這樣的算法冤灾。
這樣的做法,明顯有個不合理的部分辕近。那就是頻率峰值可能不均分韵吨,例如,雖然設(shè)置的是1分鐘訪問5次亏推,但假設(shè)訪問都集中在11:00:40学赛,這樣子,11點11分確實只訪問了5次吞杭。接下來盏浇,11:01:00數(shù)據(jù)清除,11:01:15秒有5次訪問芽狗,也符合規(guī)范绢掰。然而, 11:00:4011:01:15這段時間(不足1分鐘)童擎,卻能訪問10次滴劲!

中間這段時間,其實超標啦

看來這樣的方法也不行顾复,問題在于:

  1. 不能在周期邊界暴力清空
  2. 隨著時間推移班挖,確實需要清掉一些舊的不用了的數(shù)據(jù)

基于這兩點,于是有了最終比較符合需求的算法:滑動窗口計數(shù)(Sliding window counters)芯砸。我突然意識到這個方法萧芙,是因為前段時間瞄了一下TCP協(xié)議(真是牛逼的協(xié)議啊)假丧,然后網(wǎng)上一查双揪,發(fā)現(xiàn)早就被別人提出來了(見文末參考文檔)。

算法思路在于包帚,不是單純地記錄每次請求的時間戳(開頭說了渔期,可能太耗空間),而是把請求按照一段一段計數(shù)渴邦。比如疯趟, 1分鐘5次這樣的要求,可以把一分鐘劃分成60秒几莽,然后每秒只用一個數(shù)字表示這一秒有多少個請求迅办。這樣,請求再多章蚣,也只需要60個數(shù)字記錄(因為分成了60份)。同理,1小時100次纤垂,可以把時間劃分成分鐘矾策,進行記錄。
然后峭沦, 每次有新請求來的時候贾虽,刪除已經(jīng)沒用的數(shù)據(jù)(超過限定期限的,比如上面說的1小時)吼鱼,然后算出時間戳蓬豁,計數(shù)增加。如果沒有超過限制菇肃,那么地粪,就設(shè)置整個數(shù)據(jù)(下面示例中的“user_A")的過期時間(如果以后用戶都不訪問了, 這些數(shù)據(jù)會在過期之后被回收掉)琐谤。

一個用戶的記錄示例:
"user_A": {"11:00:00": 5, "11:01:00": 3}

份數(shù)劃分的意義何在呢蟆技?顯然首先是為了省內(nèi)存(同時統(tǒng)計也快),其次是為了控制誤差斗忌。事實上质礼,這個算法是有誤差的。比如假設(shè)1小時被劃分成60份织阳, 也就是每分鐘一份眶蕉,11:00:40的訪問會被記錄在11點整上, 而12:00:10會被記錄在12點整上唧躲,這兩個整點其實在不同的時間段造挽,也就是說考慮12點整的訪問時,已經(jīng)不用去考慮11點整的訪問量了惊窖。而實際上刽宪,11:00:4012:00:10的相差是不足一個小時的,邏輯上它們的訪問量應(yīng)該算在同一個小時里界酒。

不過圣拄,實際中,算法實現(xiàn)的時候毁欣,應(yīng)該能接受這樣的誤差(如果不能接受庇谆,需要在清楚過期數(shù)據(jù)的時候,注意這樣的邊界問題凭疮,比如額外保留一份小時間段的數(shù)據(jù)饭耳。因為算法本身無法區(qū)分11:00:0011:00:40這樣的訪問)。
這個算法設(shè)置好合理的劃分(如果用redis执解,不要超過128寞肖,因為效率),自己估算好最大誤差值(很顯然,極端情況下新蟆,依然可以在同一個時間段內(nèi)允許兩倍的訪問)觅赊,應(yīng)該可以在實際運用中起到比較好的效果了。

說了這么多琼稻,我在Github上搜了一下吮螺,似乎還沒有Golang對應(yīng)的實現(xiàn)。接下來帕翻,我會想辦法抽時間實現(xiàn)一下鸠补。

更新:
實現(xiàn)過程中,滑動窗口計數(shù)的時候嘀掸,發(fā)現(xiàn)太多需要改動一段一段計數(shù)的地方紫岩。感覺用hash不如序列化然后用string存取快。

實現(xiàn)地址:
restrictor

參考文章:
https://blog.figma.com/an-alternative-approach-to-rate-limiting-f8a06cf7c94c

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末横殴,一起剝皮案震驚了整個濱河市被因,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衫仑,老刑警劉巖梨与,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異文狱,居然都是意外死亡粥鞋,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門瞄崇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呻粹,“玉大人,你說我怎么就攤上這事苏研〉茸牵” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵摹蘑,是天一觀的道長筹燕。 經(jīng)常有香客問我,道長衅鹿,這世上最難降的妖魔是什么撒踪? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮大渤,結(jié)果婚禮上制妄,老公的妹妹穿的比我還像新娘。我一直安慰自己泵三,他們只是感情好耕捞,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布衔掸。 她就那樣靜靜地躺著,像睡著了一般砸脊。 火紅的嫁衣襯著肌膚如雪具篇。 梳的紋絲不亂的頭發(fā)上纬霞,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天凌埂,我揣著相機與錄音,去河邊找鬼诗芜。 笑死瞳抓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的伏恐。 我是一名探鬼主播孩哑,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼翠桦!你這毒婦竟也來了横蜒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤销凑,失蹤者是張志新(化名)和其女友劉穎丛晌,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斗幼,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡澎蛛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蜕窿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谋逻。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖桐经,靈堂內(nèi)的尸體忽然破棺而出毁兆,到底是詐尸還是另有隱情,我是刑警寧澤阴挣,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布气堕,位于F島的核電站,受9級特大地震影響屯吊,放射性物質(zhì)發(fā)生泄漏送巡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一盒卸、第九天 我趴在偏房一處隱蔽的房頂上張望骗爆。 院中可真熱鬧,春花似錦蔽介、人聲如沸摘投。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽犀呼。三九已至幸撕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間外臂,已是汗流浹背坐儿。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宋光,地道東北人貌矿。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像罪佳,于是被迫代替她去往敵國和親逛漫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容