首页 > 数据库 >【重复造轮子】基于Redis的RateLimiter

【重复造轮子】基于Redis的RateLimiter

时间:2022-09-06 15:22:09浏览次数:110  
标签:redis RateLimiter -- latestTime Redis remainToken token 轮子 local

造轮子的过程也是学习的过程。

如果公司的 Redis 不支持发布订阅指令的话,是没法用 Redisson 的,因为 Redisson 的大部分功能都依赖于 Redis 的发布订阅指令。

这是完整实现的代码仓库:https://gitee.com/wu0916/redis-rate-limiter

下面这段 lua 代码是基于 Redis 的 RateLimiter 的实现:

local maxToken = tonumber(ARGV[1])      -- 单位时间内的最大 token 数
local intervalTime = tonumber(ARGV[2])  -- 生成一个 token 的间隔毫秒数
local curTime = tonumber(ARGV[3])       -- 当前时间的毫秒数
local remainToken                       -- 当前可用的 token 数

local latestTime = redis.call("HGET", KEYS[1], "latestTime")    -- 上次生成 token 的时间

-- 将当前时间对齐到 intervalTime
-- 比如 intervalTime 是 200,当前时间是 1662444699797,则对齐后的时间就是 1662444699600
local alignTime = curTime - (curTime % intervalTime)

if latestTime then
    -- 获取剩余可以用 token 数
    remainToken = tonumber(redis.call("HGET", KEYS[1], "remainToken"))

    -- 计算与上次生成 token 的时间差,是否允许再次生成一个 token
    local diffTime = alignTime - tonumber(latestTime)

    -- 与上次生成时间相差不到 1秒
    if diffTime < 1000 then
        -- 计算可以生成几个 token
        local newTokenNum = math.floor(diffTime / intervalTime)
        -- 将新生成的 token 累加到剩余 token 中,然后更新生成 token 的时间
        if newTokenNum > 0 then
            remainToken = remainToken + newTokenNum
            redis.call("HSET", KEYS[1], "latestTime", alignTime)
        end
    elseif diffTime == 1000 then
        -- 新的一秒的开始
        remainToken = 1
        redis.call("HSET", KEYS[1], "latestTime", alignTime)
    else
        -- 计算到整秒时间戳的差
        diffTime = alignTime - (curTime - (curTime % 1000))
        local newTokenNum = math.floor(diffTime / intervalTime)
        if newTokenNum > 0 then
            remainToken = remainToken + newTokenNum
            redis.call("HSET", KEYS[1], "latestTime", alignTime)
        end
     end
else
    -- 第一次获取,先放入一个 token,然后初始化刷新时间
    remainToken = 1
    redis.call("HSET", KEYS[1], "latestTime", alignTime)
end
if remainToken <= 0 then
    redis.call("HSET", KEYS[1], "remainToken", 0)
    return 0
else
    redis.call("HSET", KEYS[1], "remainToken", remainToken - 1)
    return 1
end

有任何问题欢迎提出。

 

标签:redis,RateLimiter,--,latestTime,Redis,remainToken,token,轮子,local
From: https://www.cnblogs.com/wuqinglong/p/16661930.html

相关文章

  • Redis脑裂问题 和 处理办法
    背景假设现在有三台机器,分别安装了redis服务,结构如图故障发生:如果此时master服务器所在区域网络通信出现异常,导致和两台slave机器无法正常通信,但是和客户端的连接是正常......
  • 新增一个Redis 从节点为什么与主节点的key数量不一样呢?
    在日常的Redis运维过程中,经常会发生重载RDB文件操作,主要情形有:主从架构如果主库宕机做高可用切换,原从库会挂载新主库重新获取数据主库QPS超过10万,需要做读写分离,......
  • 最新一线大厂Redis使用21条军规及详细解读
    说明:个人原创,本人在一线互联网大厂维护着几千套集群,关于redis使用的一些坑进行了经验总结,希望能给大家带来一些帮助适用场景:并发量大、访问量大的业务规范:介绍军规内......
  • Redis的高可用Sentinel
    Redis的高可用Sentinel什么是SentinelRedis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的......
  • Redis总结
    Redis底层数据结构当数据量小,通过数组实现的压缩数据结构用下标访问更快;当数据量大,维护数组的元数据占用空间随之增长,所以使用普通存储redis支持<string,valu......
  • 【转】spring-session-data-redis核心原理
    这个组件的核心本质就是在实现单点登录SSO问题,将用户的登录session信息从原来的存储在jvm中转移到redis中去,微服务架构下每个应用接到请求都不会从自己的节点解析用户登录......
  • 11-redis集群
    redis集群搭建#搭建三主三从redis集群#redis5.0提供了集群快速搭建#修改脚本文件:redis/utils/create-cluster目录下的create-cluster脚本文件--bind$IP--mast......
  • redis分布锁
    1.redis分布式锁应用的场景?1)防止缓存穿透:热点数据过期,大量线程访问mysql2) 防止秒杀超卖:库存数量同步给redis后,对redis数据进行扣减3)双写一致性:缓存的数据,被修改,导致......
  • redis面试题2
    1、现在有个场景,一个key内容很大(几十M),一个key是热点,你如何优化?2、如何优雅的删除这个大key?3、redis的存储结构?4、实现map的方法除了哈希还有哪些?5、redis的setnx底层怎......
  • redis面试题
    1、redis和mwmcached的区别2、缓存数据的处理流程是怎样的3、为什么要用redis/为什么要用缓存4、Redis常见数据结构以及使用场景5、Redis单线程模型详解6、Redis没有......