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

        }


    }
相关推荐
独泪了无痕2 小时前
Spring Data Redis 快速上手
spring boot·redis·后端
IT19952 小时前
Fail2Ban 防护 MySQL 实战|登录失败 3 次,IP 封禁 24 小时
数据库·mysql
夕除2 小时前
redis--IO 多路复用(select + poll)
数据库·sql
lzhdim6 小时前
100条常用SQL语句
数据库·sql·mysql·mybatis
天河归来6 小时前
从原始消息到业务数据:三层数据架构的设计与实践
数据库·数据仓库·架构
数据库小学妹6 小时前
金融数据库成本怎么算?五笔钱加一张TCO表
数据库·金融行业·数据库选型·国产化替代·tco·金融数据库
KaiwuDB7 小时前
KaiwuDB 分布式集群扩缩容,从原理到完整操作踩坑总结
运维·数据库·分布式
用户52958931668507 小时前
三马代驾实战:抢单池的 Redis 锁 + RabbitMQ 异步消费怎么做
redis
auspicious航7 小时前
PostgreSQL的备份与恢复
数据库·postgresql
这个DBA有点耶7 小时前
从 MySQL 到时序数据库:我帮朋友做迁移的完整记录
数据库·架构·dba