使用Redis实现四大主流限流策略
发表时间: 2021-05-30 14:02
@RequestMapping(value = "/start",method = RequestMethod.GET) public Map<String,Object> start(@RequestParam Map<String, Object> paramMap) { return testService.startQps(paramMap); }
@Overridepublic 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;}
@RequestMapping(value = "/startList",method = RequestMethod.GET) public Map<String,Object> startList(@RequestParam Map<String, Object> paramMap) { return testService.startList(paramMap); }
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;
@RequestMapping(value = "/startLoutong",method = RequestMethod.GET)public Map<String,Object> startLoutong(@RequestParam Map<String, Object> paramMap) { return testService.startLoutong(paramMap);}
@Overridepublic 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;}
@Componentpublic 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); } }
原文链接:
https://juejin.cn/post/6967704472109711367