当前位置:首页 > 记忆回溯 > 正文内容

go gin框架实现限流

MuWinds4个月前 (11-05)记忆回溯122

接手一个项目,甲方希望在项目中实现指定用户的限流,这需要我们在go项目中实现一个限流器。

限流器的实现有很多经典的思想,不过令牌桶的思路简单,运行效率高,它是以恒定的速度往木桶里加入令牌,木桶满了则不再加入令牌。

服务收到请求时尝试从木桶中取出一个令牌,如果能够得到令牌则继续执行后续的业务逻辑。如果没有得到令牌,直接返回访问频率超限的错误码或页面等,不继续执行后续的业务逻辑。

图片

特点:由于木桶内只要有令牌,请求就可以被处理,所以令牌桶算法可以支持突发流量。

同时由于往木桶添加令牌的速度是恒定的,且木桶的容量有上限,所以单位时间内处理的请求书也能够得到控制,起到限流的目的。

假设加入令牌的速度为 1token/10ms,桶的容量为500,在请求比较的少的时候(小于每10毫秒1个请求)时,木桶可以先"攒"一些令牌(最多500个)。

当有突发流量时,一下把木桶内的令牌取空,也就是有500个在并发执行的业务逻辑,之后要等每10ms补充一个新的令牌才能接收一个新的请求。

不过官方已经写好了令牌桶的限流器,我们直接拿过来写好中间件放到路由就好~

middleware/rateLimit.go

package middleware

import (
    "IpDatabase/model"
    "sync"

    "github.com/gin-gonic/gin"
    "golang.org/x/time/rate"
)

var limiterMap = make(map[string]*rate.Limiter)
var mu sync.Mutex

// getLimiter 获取或创建一个特定 key 的限流器
func getLimiter(key string) *rate.Limiter {
    mu.Lock()
    defer mu.Unlock()

    // 如果限流器已经存在,返回现有的限流器
    if limiter, exists := limiterMap[key]; exists {
        return limiter
    }

    // 否则,创建一个新的限流器
    key_limit_info, err := model.ListUser(&model.UserInfo{
        Api_key: key,
    })
    if err != nil {
        return nil
    }
    limiter := rate.NewLimiter(rate.Limit(key_limit_info[0].ReqRate), key_limit_info[0].ReqRate) // 每秒1个请求,突发3个请求
    limiterMap[key] = limiter
    return limiter
}

// 限流中间件,基于用户的 key(如API Key或User ID)
func RateLimiterByKey(c *gin.Context) {
    // 假设用户通过 `Authorization` header 提供 key
    key := c.GetHeader("Authorization")

    // 如果没有提供 key,返回错误
    if key == "" {
        BadResponse("API Key is required", c)
        return
    }

    // 获取或创建限流器
    limiter := getLimiter(key)

    // 检查是否允许请求
    if !limiter.Allow() {
        BadResponse("Too many requests", c)
        return
    }
    // 如果通过限流器,继续处理请求
    c.Next()
}

写进路由

func setApiRouter(engine *gin.Engine) {
    apiRouter := engine.Group("/api")
    {
        apiRouter.GET("/search_ip_info", middleware.IsExpiredKey(), middleware.RateLimiterByKey, controller.SearchIp)
    }
}

打完收工!

“go gin框架实现限流” 的相关文章

中学电学必修:电表电路原理

初中的时候老师告诉我们看电压表电流表在电路里时,将电流表充当导线,电压表充当断路。这里简单说一下原因。任何一个电压表和电流表都由灵敏电流计配合大电阻组成:原理图可以看出:电流表中的R用来分G的电流,并以此来达到更大的量程;电压表的R用来分G的电压,也可以得到更大的量程。灵敏电流计是有电阻的,但是电阻...

PHP 程式碼風格PSR

PSR-1:基本程式寫作標準1. 總覽檔案只能使用 <?php 和 <?= 標籤檔案字元編碼只能用 UTF-8 檔首無 BOM檔案應該只宣告符號 (class、function、constant)或是造成副作用(例如產生輸出、修改 .ini 檔之類)兩者擇一不應該兩個都做Namespac...

两个物块动量定理的二级结论整理

还是那样子,死记硬背没用这就是纯纯算数的活儿,理儿都摆在这了。一个经典的模型是一个物块以速度v撞向另外一个静止的物块,符合动量守恒:思考题:两个滑块相互碰撞,仍然是理想模型,动量守恒能量守恒,推导v1/v2...

AMD Ryzen Windows睡死问题解决

更新AMD芯片组驱动(不分任何笔记本厂家): https://seaou.lanzouw.com/iQL0V2m7wnuh...

数据结构——堆(Heap)大根堆、小根堆

转载:https://www.cnblogs.com/wangchaowei/p/8288216.htmlHeap是一种数据结构具有以下的特点:1)完全二叉树;2)heap中存储的值是偏序;Min-heap: 父节点的值小于或等于子节点的值;Max-heap: 父节点的值大于或等于子节点的值;堆的存...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。