在线时间: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 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); Map<string, object=""> map = new HashMap<>(); map.put("success", "success"); return map; 结果测试:
四、漏桶算法
优点:
缺点:
实现: 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限流策略的资料请关注极客世界其它相关文章! |
请发表评论