Skip to content

Commit

Permalink
增加滑动窗口限流
Browse files Browse the repository at this point in the history
  • Loading branch information
taoshihan1991 committed Dec 14, 2020
1 parent d55f585 commit af4dd92
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 0 deletions.
21 changes: 21 additions & 0 deletions controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controller
import (
"github.com/gin-gonic/gin"
"github.com/taoshihan1991/miaosha/redis"
"log"
)

func checkUserLogin(c *gin.Context) (string, bool) {
Expand All @@ -18,3 +19,23 @@ func checkUserLogin(c *gin.Context) (string, bool) {

return info, 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
//}
if !redis.LimitFreqs(key, count, timeWindow) {
c.JSON(200, gin.H{
"code": 400,
"msg": "error Current IP frequently visited",
})
log.Println("key:" + key + " error Current IP frequently visited")
return false
}
return true
}
4 changes: 4 additions & 0 deletions controller/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (
)

func GetProduct(c *gin.Context) {
if !limitIpFreq(c, 10, 2) {
return
}

id := c.Query("id")
redis.NewRedis()

Expand Down
28 changes: 28 additions & 0 deletions redis/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/go-redis/redis/v8"
"github.com/taoshihan1991/miaosha/setting"
"log"
"strconv"
"sync"
"time"
)
Expand Down Expand Up @@ -141,9 +142,36 @@ func ListLen(key string) int64 {
}
return res
}
func ListIndex(key string, index int64) string {
res, err := rdb.LIndex(ctx, key, index).Result()
if err != nil {
log.Println(err.Error())
return ""
}
return res
}
func DelKey(key string) {
_, err := rdb.Del(ctx, key).Result()
if err != nil {
log.Println(err.Error())
}
}
func LimitFreqs(queueName string, count uint, timeWindow int64) bool {
currTime := time.Now().Unix()
length := uint(ListLen(queueName))
if length < count {
ListPush(queueName, currTime)
return true
}
//队列满了,取出最早访问的时间
earlyTime, _ := strconv.ParseInt(ListIndex(queueName, int64(length)-1), 10, 64)
//说明最早期的时间还在时间窗口内,还没过期,所以不允许通过
if currTime-earlyTime <= timeWindow {
return false
} else {
//说明最早期的访问应该过期了,去掉最早期的
ListPop(queueName)
ListPush(queueName, currTime)
}
return true
}
33 changes: 33 additions & 0 deletions utils/limits.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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
}

0 comments on commit af4dd92

Please sign in to comment.