本代碼基于原博客java版本的GO實作 , 原文解釋也比較詳細 , 這里也放上原文鏈接:https://www.cnblogs.com/dijia478/p/13807826.html
具體解釋如下 , 代碼在最下面
1.10秒內通過5次 , 這條線就是佇列list,當第一個事件進來,佇列大小是0,時間是第1秒:

2.因為size=0,小于5,都沒有到限制的次數,完全不用考慮時間視窗,直接把這次事件的時間戳放到0的位置:

3.第2.8秒的時候,第二個事件來了,因為此時size=1,還是小于5,把這次事件的時間戳放到0的位置,原來第1秒來的事件時間戳會往后移動一格:

4.陸續的又來了3個事件,佇列大小變成了5,先來的時間戳依次向后移動,此時,第6個事件來了,時間是第8秒:

5.因為size=5,不小于5,此時已經達到限制次數,以后都需要考慮時間視窗了,所以取出位置4的時間(離現在最遠的時間),和第6個事件的時間戳做比較:

6.得到的差是7秒,小于時間視窗10秒,說明在10秒內,來的事件個數大于5了,所以本次不允許通過:

7.接下來即便來上100個事件,只要時間差小于等于10秒,都同上,拒絕通過:

8.第11.1秒,第101次事件過來了,因為size=5,不小于5,所以取出位置4的時間(離現在最遠的時間),和第101個事件的時間戳做比較:

9.得到的差是10.1秒,大于時間視窗10秒,說明在10秒內,來的事件個數小于等于5了,所以本次允許通過:

10.洗掉位置4的時間(離現在最遠的時間),把這次事件的時間戳放到0的位置,后面的時間戳依次向后移動:

往后再來其他事件,就是重復4-10的步驟,即可實作,在任意滑動時間視窗內,限制通過的次數
其本質思想是轉換概念,將原本問題的確定時間大小,進行次數限制,轉換成確定次數大小,進行時間限制,
package utils import "time" var LimitQueue map[string][]int64 var ok bool //單機時間滑動視窗限流法 func LimitFreqSingle(queueName string, count uint, timeWindow int64) bool { currTime := time.Now().Unix() if LimitQueue == nil { LimitQueue = make(map[string][]int64) } if _, ok = LimitQueue[queueName]; !ok { LimitQueue[queueName] = make([]int64, 0) } //佇列未滿 if uint(len(LimitQueue[queueName])) < count { LimitQueue[queueName] = append(LimitQueue[queueName], currTime) return true } //佇列滿了,取出最早訪問的時間 earlyTime := LimitQueue[queueName][0] //說明最早期的時間還在時間視窗內,還沒過期,所以不允許通過 if currTime-earlyTime <= timeWindow { return false } else { //說明最早期的訪問應該過期了,去掉最早期的 LimitQueue[queueName] = LimitQueue[queueName][1:] LimitQueue[queueName] = append(LimitQueue[queueName], currTime) } return true }
使用的案例:
func limitIpFreq(c *gin.Context, timeWindow int64, count uint) bool { ip := c.ClientIP() key := "limit:" + ip if !utils.LimitFreqSingle(key, count, timeWindow) { c.JSON(200, gin.H{ "code": 400, "msg": "error Current IP frequently visited", }) return false } return true }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/234592.html
標籤:Go
