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

        }


    }
相关推荐
viskaz29 分钟前
1-向量数据库概览
数据库·embedding
这个DBA有点耶1 小时前
实时数据集成工具选型2026:从CDC到数据同步的完整指南
数据库·数据挖掘·dba
__zRainy__1 小时前
Node系列 · ORM:Sequelize 简介
数据库·后端·node.js
鸽芷咕1 小时前
达梦VS金仓选型实录:别只比TPC-C,迁移工具链才是项目成败的关键
数据库
King of fraud2 小时前
Linux 下 MySQL 基础操作:创建用户、数据库与权限管理实战
linux·数据库·mysql
努力的小雨2 小时前
sys_basebackup 适合什么场景,先看恢复目标
数据库
这个DBA有点耶3 小时前
Redis大key“根治”指南:拆分策略与数据结构选型
数据库·mysql·架构
程序员与背包客_CoderZ3 小时前
高性能分布式KV存储引擎RocksDB入门与C/C++编码实战
c语言·开发语言·数据库·c++·分布式·分布式数据库·rocksdb
进击的_鹏3 小时前
从零开始的 Redis 学习
服务器·数据库·c++·redis·缓存
隔窗听雨眠3 小时前
当KES遇到多租户:金仓数据库多租户架构的隔离实践与部署指南
数据库·架构