基于Redis实现限流

限流尽可能在满足需求的情况下越简单越好!

1、基于Redsi的increment方法实现固定窗口限流

  • Redis的increment方法保证并发线程安全

  • 窗口尽可能越小越好(太大可能某一小段时间就打满请求剩下的都拿不到令牌了)

  • 这个原理其实就是用当前时间戳然后除窗口大小 在这个窗口大小的时间内 key都一样

    public class RedisRateLimiter {

    复制代码
      private final StringRedisTemplate redisTemplate;
      // 命令前缀
      private final String key;
    
      private final int rate;
    
      private final int window;
    
      public RedisRateLimiter(StringRedisTemplate redisTemplate, String key, int rate,int window) {
          this.redisTemplate = redisTemplate;
          this.key = key;
          this.rate = rate;
          Assert.isTrue(window > 0 && window <= 60,"窗口只支持分钟内");
          this.window = window;
      }
    
      // 检查并获取令牌
      public boolean acquire() {
          String currentKey = key + "_" + (DateUtil.currentSeconds() / window);
    
          Long currentCount = redisTemplate.opsForValue().increment(currentKey);
    
          redisTemplate.expire(currentKey, window, TimeUnit.SECONDS);
    
          if (currentCount > rate){
              return false;
          }
          return true;
      }
    
    
      public void acquireSleep() {
          int count = 0;
          while (!acquire()){
              ThreadUtil.sleep(1,TimeUnit.SECONDS);
              count++;
              log.info("RedisRateLimiter[{}] try acquire sleep {}",key,count);
          }
      }
    
      public boolean acquireSleep(int waitSecond) {
          int count = 0;
          while (!acquire()){
              if (count >= waitSecond){
                  return false;
              }
              ThreadUtil.sleep(1,TimeUnit.SECONDS);
              count++;
              log.info("RedisRateLimiter[{}] try acquire sleep {}",key,count);
          }
          return true;
      }

    }

使用案例:

下面这个任务是实时请求评论和子评论接口,但是两个接口每分钟不能超过100,所以我们使用限流限制10秒不超过18即可也能满足需求。

复制代码
public class ScCommentRealTimeSyncTask  {
        private RedisRateLimiter rateLimiter;

        @PostConstruct
        public void init(){
            rateLimiter = new
                    RedisRateLimiter(stringRedisTemplate,KAOLA_COMMENT_RATE_KEY,16,10);
        }

        @Scheduled(fixedDelay = 3000)
        public void task(){
            // 请求接口1
            rateLimiter.acquireSleep();
            request1();
            
            //请求接口2
            rateLimiter.acquireSleep();
            request2();

        }


    }
相关推荐
爱写代码的阿森1 小时前
鸿蒙三方库 | harmony-utils之KvUtil键值型数据库操作详解
数据库·华为·harmonyos·鸿蒙·huawei
Database_Cool_2 小时前
单机 MySQL 迁移到分布式数据库方便吗?阿里云 PolarDB-X 100% MySQL 协议兼容零改造平滑迁移
数据库·分布式·mysql
姜太小白2 小时前
【MySQL】 索引优化实战:解决 WHERE 等值 + IS NULL 查询,TEXT 字段报错 1167 的完整指南
数据库·mysql
窝子面3 小时前
手搓最简前后端协作-node
javascript·数据库
吳所畏惧3 小时前
宝塔面板Redis密码修改指南:SSH命令修改 vs 面板UI界面修改,哪个更靠谱?
运维·服务器·数据库·redis·缓存·ssh
DFT计算杂谈3 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
HPFBoy3 小时前
log4net 数据库存日志正确配置
数据库
赵丙双4 小时前
Redis 概率相关的数据类型
redis
liuxiaowei34 小时前
【绝版教程】新版MySQL DBA高级实战进阶班 MySQL8.0 姜承尧-腾讯数据库总监
数据库·mysql·dba