redis实现的四种常见限流策略

redis实现的四种常见限流策略

目录

          引言

          固定时间窗口算法

          优点

          缺点

          实现

          controller

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

          service

          @Override
          public Map<string, object=""> startQps(Map<string, 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");
              }
              //返回成功告知
              Map<string, object=""> map = new HashMap<>();
              map.put("success", "success");
              return map;
          }

          结果测试

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

          滑动时间窗口算法

          优点

          缺点

          实现

          controller

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

          service

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

          结果测试

          漏桶算法

          优点

          缺点

          实现

          controller

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

          service

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

          @Override
          public Map<string, object=""> startLoutong(Map<string, 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");
              }
              Map<string, 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 Map<string, object=""> startLingpaitong(Map<string, object=""> paramMap) {
                  String redisKey = "lingpaitong";
                  String token = redisTemplate.opsForList().leftPop(redisKey).toString();
                  //正常情况需要验证是否合法,防止篡改
                  if (StringUtils.isEmpty(token)) {
                      throw new RuntimeException("令牌桶拒绝");
                  }
                  Map<string, 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 限流策略内容请搜索趣讯吧以前的文章或继续浏览下面的相关文章希望大家以后多多支持趣讯吧!

          发布于 2021-06-19 06:12:37
          收藏
          分享
          海报
          0 条评论
          211
          上一篇:捕获与解析Android(NativeCrash) 下一篇:详解dex优化对Arouter查找路径的影响
          目录

            0 条评论

            本站已关闭游客评论,请登录或者注册后再评论吧~

            忘记密码?

            图形验证码