美文网首页
基于redis实现令牌桶

基于redis实现令牌桶

作者: 林海畅游 | 来源:发表于2023-08-06 19:44 被阅读0次
package ratelimit

import (
    "fmt"

    "code.byted.org/gopkg/logs"
    "code.byted.org/ttarch/hermes_go_api/dal/redis"
)

const (
    lua = `redis.replicate_commands()

local tokens_key = KEYS[1]    //令牌桶key
local timestamp_key = KEYS[2]  //最后一次更新令牌桶的时间戳
local rate = tonumber(ARGV[1])  // 令牌产生的速率
local capacity = tonumber(ARGV[2])  //令牌桶容量
local requested = tonumber(ARGV[3]) //所需的令牌数量
local now_time = redis.call('TIME')
local now = now_time[1]*1000000+now_time[2]  //获取当前微秒时间戳

local fill_time = capacity/rate   //生成所有令牌(令牌桶填满)所需要的时间
local ttl = math.floor(fill_time*2)  //缓存时间

local last_tokens = tonumber(redis.call("get", tokensxkey))  //获取令牌桶剩余的令牌数量
if last_tokens == nil then
  last_tokens = capacity  //剩余令牌数初始化为容量大小
end

local last_refreshed = tonumber(redis.call("get", timestamp_key))  // 上次一令牌桶更新的时间戳
if last_refreshed == nil then
  last_refreshed = 0  // 第一次为0
end

local delta = math.floor(math.max(0, now-last_refreshed)*rate/1000000)  // 计算当前时间内新增的令牌数
local filled_tokens = math.min(capacity, last_tokens+delta)  //计算令牌桶里的令牌总数
local allowed = filled_tokens >= requested  //是否有足够的令牌处理请求
local new_tokens = filled_tokens
local allowed_num = 0
if allowed then
  new_tokens = filled_tokens - requested  //剩余的令牌数量 = 当前令牌数 - 所需令牌数
  allowed_num = 1
end

if ttl > 0 then
  redis.call("setex", tokens_key, ttl, new_tokens)
  redis.call("setex", timestamp_key, ttl, now-now%math.floor((1000000/rate)))
end

return allowed_num
`
)

func Acquire(uniqueKey string, qps float64) bool {
    if qps == 0 {
        return false
    }
        //1. 令牌桶数量 key 2. 最后一次更新时间key
    keys := []string{fmt.Sprintf("{%s}:tokens_key", uniqueKey), fmt.Sprintf("{%s}:timestamp_key", uniqueKey)}
    rate := qps
    requested := 1.0  // 初始化期望得到的令牌数量,默认为1
    var cap float64
    if qps >= 1 {
                // 令牌桶的容量为请求速率
        cap = rate
    } else {
                // 期望得到的令牌数量 + 请求速率乘以3
        cap = requested + rate*3
    }
    val, err := redis.DefaultRateLimitRedisCli.Eval(lua, keys, rate, cap, requested).Result()
    if err != nil {
        logs.Error("%+v", err)
        return false
    }
    valI, ok := val.(int64)
    if ok {
        return valI == 1
    }
    logs.Error("fail to parse redis result")
    return false
}

相关文章

  • Redis 实现限流-令牌桶-简单实现

    基于Redis的令牌桶算法 令牌桶算法提及到输入速率和输出速率,当输出速率大于输入速率,那么就是超出流量限制了。也...

  • 基于Redis的限流系统的设计

    本文讲述基于Redis的限流系统的设计,主要会谈及限流系统中限流策略这个功能的设计;在实现方面,算法使用的是令牌桶...

  • 基于Redis的限流系统的设计【转】

    基于Redis的限流系统的设计,主要会谈及限流系统中限流策略这个功能的设计;在实现方面,算法使用的是令牌桶算法来,...

  • 基于令牌桶算法的Java限流实现

    项目需要使用限流措施,查阅后主要使用令牌桶算法实现,为了更灵活的实现限流,就自己实现了一个简单的基于令牌桶算法的限...

  • 分布式限流 redis-cell

    redis 4.0 以后开始支持扩展模块,redis-cell 是一个用rust语言编写的基于令牌桶算法的的限流...

  • 流控的那些事儿

    令牌桶算法令牌桶控制基于令牌桶是否存在令牌可以发送流量,每一个令牌是一个字节。当请求过来会消耗桶内中的令牌。另一边...

  • 流量控制

    该库是基于令牌桶算法实现的 import "github.com/juju/ratelimit"var token...

  • 使用Redis实现令牌桶算法

    在限流算法中有一种令牌桶算法,该算法可以应对短暂的突发流量,这对于现实环境中流量不怎么均匀的情况特别有用,不会频繁...

  • SpringBoot基于RateLimiter+AOP动态的为不

    一 限流实现: RateLimiter是guava提供的基于令牌桶算法的实现类,可以非常简单的完成限流特技,并且根...

  • 基于Redis + Lua的令牌桶限流器的实现

    开发环境 jdk 11.0.10 SpringBoot 2.6.2 Idea 主要依赖 核心代码 自定义注解 限流...

网友评论

      本文标题:基于redis实现令牌桶

      本文链接:https://www.haomeiwen.com/subject/uorwpdtx.html