• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    详解基于redis实现的四种常见的限流策略

    一、引言

    二、固定时间窗口算法

    优点:

    缺点:

    实现:

    controller

    @RequestMapping(value = "/start",method = RequestMethod.GET)
    public Mapstring,object> start(@RequestParam Mapstring, object=""> paramMap) {
        return testService.startQps(paramMap);
    }

    service

    @Override
    public Mapstring, object=""> startQps(Mapstring, object=""> paramMap) {
        //根据前端传递的qps上线
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        String redisKey = "redisQps";
        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory());
        int no = redisAtomicInteger.getAndIncrement();
        //设置时间固定时间窗口长度 1S
        if (no == 0) {
            redisAtomicInteger.expire(1, TimeUnit.SECONDS);
        }
        //判断是否超限  time=2 表示qps=3
        if (no > times) {
            throw new RuntimeException("qps refuse request");
        }
        //返回成功告知
        Mapstring, object=""> map = new HashMap>();
        map.put("success", "success");
        return map;
    }

    结果测试:

    我们设置的qps=3 , 我们可以看到五个并发进来后前三个正常访问,后面两个就失败了。稍等一段时间我们在并发访问,前三个又可以正常访问。说明到了下一个时间窗口

    三、滑动时间窗口算法

    优点:

    缺点:

    实现:

    controller

    @RequestMapping(value = "/startList",method = RequestMethod.GET)
    public Mapstring,object> startList(@RequestParam Mapstring, object=""> paramMap) {
        return testService.startList(paramMap);
    }

    service

    String redisKey = "qpsZset";
    Integer times = 100;
    if (paramMap.containsKey("times")) {
        times = Integer.valueOf(paramMap.get("times").toString());
    }
    long currentTimeMillis = System.currentTimeMillis();
    long interMills = inter * 1000L;
    Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis);
    if (count > times) {
        throw new RuntimeException("qps refuse request");
    }
    redisTemplate.opsForZSet().add(redisKey, UUID.randomUUID().toString(), currentTimeMillis);
    Mapstring, object=""> map = new HashMap>();
    map.put("success", "success");
    return map;

    结果测试:

    四、漏桶算法

    优点:

    缺点:

    实现:

    controller

    @RequestMapping(value = "/startLoutong",method = RequestMethod.GET)
    public Mapstring,object> startLoutong(@RequestParam Mapstring, object=""> paramMap) {
        return testService.startLoutong(paramMap);
    }

    service在service中我们通过redis的list的功能模拟出桶的效果。这里代码是实验室性质的。在真实使用中我们还需要考虑并发的问题

    @Override
    public Mapstring, object=""> startLoutong(Mapstring, object=""> paramMap) {
        String redisKey = "qpsList";
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        Long size = redisTemplate.opsForList().size(redisKey);
        if (size >= times) {
            throw new RuntimeException("qps refuse request");
        }
        Long aLong = redisTemplate.opsForList().rightPush(redisKey, paramMap);
        if (aLong > times) {
            //为了防止并发场景。这里添加完成之后也要验证。  即使这样本段代码在高并发也有问题。此处演示作用
            redisTemplate.opsForList().trim(redisKey, 0, times-1);
            throw new RuntimeException("qps refuse request");
        }
        Mapstring, object=""> map = new HashMap>();
        map.put("success", "success");
        return map;
    }

    下游消费

    @Component
    public class SchedulerTask {
    
        @Autowired
        RedisTemplate redisTemplate;
    
        private String redisKey="qpsList";
    
        @Scheduled(cron="*/1 * * * * ?")
        private void process(){
            //一次性消费两个
            System.out.println("正在消费。。。。。。");
            redisTemplate.opsForList().trim(redisKey, 2, -1);
        }
    
    }

    测试:

    五、令牌桶算法

    public Mapstring, object=""> startLingpaitong(Mapstring, object=""> paramMap) {
        String redisKey = "lingpaitong";
        String token = redisTemplate.opsForList().leftPop(redisKey).toString();
        //正常情况需要验证是否合法,防止篡改
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("令牌桶拒绝");
        }
        Mapstring, object=""> map = new HashMap>();
        map.put("success", "success");
        return map;
    }
    @Scheduled(cron="*/1 * * * * ?")
    private void process(){
        //一次性生产两个
        System.out.println("正在消费。。。。。。");
        for (int i = 0; i  2; i++) {
            redisTemplate.opsForList().rightPush(redisKey, i);
        }
    }

    以上就是详解基于redis实现的四种常见的限流策略的详细内容,更多关于redis限流策略的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • redis实现的四种常见限流策略
    • springboot+redis 实现分布式限流令牌桶的示例代码
    • 详解Redis实现限流的三种方式
    • Python+redis通过限流保护高并发系统
    • Springboot使用redis进行api防刷限流过程详解
    • Redis和Lua实现分布式限流器的方法详解
    • php使用lua+redis实现限流,计数器模式,令牌桶模式
    • 基于Redis的限流器的实现(示例讲解)
    • 基于Redis实现分布式应用限流的方法
    上一篇:Redis基于Bitmap实现用户签到功能
    下一篇:详解redis缓存与数据库一致性问题解决
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    详解基于redis实现的四种常见的限流策略 详解,基于,redis,实现,的,