当前位置:首页 > 运维 > 正文内容

go gin框架实现限流

MuWinds3个月前 (11-05)运维109

接手一个项目,甲方希望在项目中实现指定用户的限流,这需要我们在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框架实现限流” 的相关文章

OpenWrt无法保存配置无法生效的解决方法

原因:意外断电导致硬盘卡在只读状态进入openwrt后台按回车输入下面命令,重新挂载即可:mount -o remount rw /2024.07.10更新:换了官方固件后因为要拆下来换机箱散热器又是一次意外断电,卡在了只读状态,但是这次重新挂载无用了。现在这...

zblog强制打开调试模式

之前写zblog of cloudflare插件的时候,写错了代码,因为没开调试模式我也不知道哪里报错,这里记录一下:修改 zb_system/function/c_system_base.php,将第 22 行的//注释删除掉,再保存即可。...

Zerotier配合Nginx实现内网穿透

之前博客网站一直用的家里机器配合香港Azure做frp内网穿透,用CF CDN进行数据分发,不提frp的虚拟局域网模式在跨国数据传输时面临的数据审查和路由方向会给速度及稳定性造成非常大的影响,其可能有的内存溢出和服务重启时的持续掉线问题也是很抓狂的,在这里,使用zerotier为两机打洞连接p2p,...

CentOS Python后台运行

nohup python /data/python/server.py > python.log3 2>&1 &说明:1、1是标准输出(STDOUT)的文件描述符,2是标准错误(STDERR)的文件描述符 &nb...

node-saas问题

构建vue项目的时候报错:很简单,nodejs版本太新了,直接换到dart-sassyarn remove node-sass yarn add sass...

记录一个远古垃圾系统的维护

这次接手的是tp框架的远古收款系统,开局几个ajax认不上我已经习以为常了,反手把php版本改成7.0就恢复正常(7.0算是个兼容版本 5.x的和7.x都兼容一点 各位穷途末路了可以试试)然后呢,其他的确认过没啥毛病了,打算测试一下接口的时候,意外就来了,弹404。我知道tp框架弹404一定是代码的...

发表评论

访客

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