利用Redis实现访问次数限流的方法详解

 更新时间:2022年02月22日 08:59:44   作者:架构摆渡人  
这篇文章主要给大家介绍了关于如何利用Redis实现访问次数限流的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

假设我们要做一个业务需求,这个需求就是限制用户的访问频次。比如1分钟内只能访问20次,10分钟内只能访问200次。因为是用户维度的场景,性能肯定是要首先考虑,那么适合这个场景的非Redis莫属。

最简单的实现,莫过于只是用incr进行计数操作,于是有了下面的代码:

long count = redisTemplate.opsForValue().increment("user:1:60");
if (count > maxLimitCount) {
   throw new LimitException("访问太频繁");
}

count = redisTemplate.opsForValue().increment("user:1:600");
if (count > maxLimitCount) {
   throw new LimitException("访问太频繁");
}

来,我们对上面这段代码解读一下。需求有2个时间维度的限制,所以这边基于用户和时间维度构建了Redis的Key。然后对每个Key进行计数,计数后的结果用于跟限制的值进行判断,如果超出了限制的值就抛出异常。

假设限制的时间场景有10个呢?那上面的代码是不是得写10遍才可以。有人可能会说,这还不简单吗?循环呀,循环确实能够解决这个问题。但是大家有没有去思考,这是用户维度的请求,如果每个请求里面都去操作10次Redis的话,这耗时至少也得10来毫秒吧。所以问题在这,并不是说这个逻辑实现的有问题。

那我们就改成批量的吧,用pipeline来批量执行。

redisTemplate.execute(new RedisCallback<Long>() {
    @Override
    public Long doInRedis(RedisConnection connection) throws DataAccessException {
        connection.openPipeline();
        connection.incr("user:1:60".getBytes());
        connection.incr("user:1:600".getBytes());
        onnection.closePipeline();
        return null;
    }
});

用pipeline也有一个问题,那就是拿不到返回值,也就只能增加,但是没办法判断是否超过了限制的阀值。

所以需要在第一步先查询下,用查到的值进行判断,这样也就是只需要和Redis交互两次就可以了。

上面的代码在单节点下没问题,但是如果在集群下,其实每个Key都可能分配到不同的节点上去,只不过是底层帮你屏蔽掉了细节,并发执行,拿到了所有结果后合并返回的。所以我们需要让所有的Key都路由到一个节点上,本来就是用户维度的,直接使用userId路由即可。

这个时候Redis的HashTag功能就排上用场了,将Key user:1:600改写成user:{1}:600 。

虽然已经优化了,但是还是要发起两次网络请求才能完成这个逻辑,有没有可能再进一步优化下呢?一次请求行不行。

这个时候要放大招了,Lua脚本走起,将所有逻辑都放入Lua脚本中,一次网络交互即可完成。

local current
current = redis.call("incr",KEYS[1])
if current == 1 then
    redis.call("expire",KEYS[1],1)
end

if current > ARGV[1]
  return 1
end

return 0

上面脚本演示了如何对一个Key进行处理,返回1表示限流,返回0表示通过。不过使用lua脚本的时候要注意,某些云服务的Redis会对脚本进行校验,像Redis的Key不能使用变量,必须用KEYS[下标]的方式,所以这里操作多个Key还不能用循环,代码得写多遍,这是一个恶心的点。

总结

到此这篇关于利用Redis实现访问次数限流的文章就介绍到这了,更多相关Redis访问次数限流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redis Scan命令的基本使用方法

    Redis Scan命令的基本使用方法

    这篇文章主要给大家介绍了关于Redis中Scan命令的基本使用方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-12-12
  • Redis利用Pipeline加速查询速度的方法

    Redis利用Pipeline加速查询速度的方法

    这篇文章主要给大家介绍了关于Redis利用Pipeline加速查询速度的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-07-07
  • Redis Template使用详解示例教程

    Redis Template使用详解示例教程

    RedisTemplate的底层通过RedisConnectionFactory对多种Redis驱动进行集成,上层通过RedisOperations提供丰富的API,并结合Spring基于泛型的bean注入,为开发提供了极大的便利,这篇文章主要介绍了Redis Template使用详解示例教程,需要的朋友可以参考下
    2023-11-11
  • Redis实现分布式锁详解

    Redis实现分布式锁详解

    这篇文章主要介绍了redis如何实现分布式锁,文章中有详细的示例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2023-04-04
  • 在项目中使用redis做缓存的一些思路

    在项目中使用redis做缓存的一些思路

    这篇文章主要介绍了在项目中使用redis做缓存的一些思路,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • Redis分布式锁的实现方式

    Redis分布式锁的实现方式

    本文主要介绍了Redis分布式锁的实现方式,分布式锁是 满足分布式系统或集群模式下多进程可见并且互斥的锁。感兴趣的同学可以参考阅读
    2023-04-04
  • Redis的缓存更新策略及最佳实践方案

    Redis的缓存更新策略及最佳实践方案

    这篇文章主要介绍了Redis的缓存更新策略及最佳实践方案,当我们向redis插入太多数据,此时就可能会导致缓存中的数据过多,所以redis会对部分数据进行更新,或者把它成为淘汰更合适,需要的朋友可以参考下
    2023-08-08
  • Redis中三种特殊数据类型命令详解

    Redis中三种特殊数据类型命令详解

    Geospatial是地理位置类型,我们可以用来查询附近的人、计算两人之间的距离等,这篇文章主要介绍了Redis中三种特殊数据类型命令详解,需要的朋友可以参考下
    2024-05-05
  • 详谈redis优化配置和redis.conf说明(推荐)

    详谈redis优化配置和redis.conf说明(推荐)

    下面小编就为大家带来一篇详谈redis优化配置和redis.conf说明(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-03-03
  • Redis中Redisson红锁(Redlock)使用原理

    Redis中Redisson红锁(Redlock)使用原理

    本文主要介绍了Redis中Redisson红锁(Redlock)使用原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08

最新评论