在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
引言
固定时间窗口算法
优点
缺点
实现
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 限流策略内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论