基于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();

        }


    }
相关推荐
阿波罗尼亚28 分钟前
数据库序列(Sequence)
数据库
Junsir大斗师1 小时前
Nginx服务器代理Postgresql-16后端数据库
数据库·nginx
Je1lyfish1 小时前
CMU15-445 (2025 Fall/2026 Spring) Project#3 - QueryExecution
linux·c语言·开发语言·数据结构·数据库·c++·算法
nj01281 小时前
Spring 循环依赖详解:三级缓存、早期引用、AOP 代理与懒加载
java·spring·缓存
m0_596749093 小时前
如何防止SQL拼接漏洞_使用PDO对象实现安全的SQL交互
jvm·数据库·python
老纪的技术唠嗑局3 小时前
深度解析 LLM Wiki / Obsidian-Wiki / GBrain:Agent 时代知识的“自组织”与“自进化”
大数据·数据库·人工智能·算法
2301_795099746 小时前
golang如何在Gin中自定义验证器_golang Gin自定义验证器实现方法
jvm·数据库·python
2301_766283446 小时前
如何在MongoDB GridFS中进行按文件大小(length)范围的查询
jvm·数据库·python
KNeeg_7 小时前
黑马点评完整代码(RabbitMQ优化)+简历编写+面试重点 ⭐
java·redis·后端·spring·面试·职场和发展·黑马点评
萧曵 丶7 小时前
MySQL 高频面试题(由浅到深 完整版,面试必背)
数据库·mysql·面试