公司前段时间需要一个限流的功能,使用场景则是在一个滑动时间段内统计某一IP的访问数量
第一次接触窗口的概念还是在学习大数据的时候,在实时处理的时候了解到的,自然而然就想到了窗口统计的操作,不过目前业务量可能还不至于吧,嗯对就是那样
无脑上呗,就利用Redis做了一个实现(不是原子性的)
我太啰嗦了,网上百度一下Redis限流很多理论和操作实践就不罗嗦了,直接上自己魔改过的
基于Redis的ZSet实现的窗口限流操作
忘记参考哪个贴了,如果有相似部分请补充一下原帖链接,代码各位取其精华去其糟粕,嗯~很可能都没了
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 
 | 
 
 
 
 
 
 
 
 
 public void windowLimit(String key, int[] windowTimes, long[] windowTime, long[] windowLimitTime, TimeUnit timeUnit, String errorMsg) {
 long currentTime = System.currentTimeMillis();
 String windowKey = WINDOW + key;
 if (redisUtils.exists(WINDOW_LIMIT + key)) {
 String[] errors = splitError(errorMsg);
 
 log.warn("当前[{}]被[{}]限制,锁定时间[{}],错误信息:[{}]", key, "窗口锁", redisUtils.getExpire(WINDOW_LIMIT + key), errors[0]);
 throw new ErrorCodeException(ErrorCodeEnum.ERROR, errors[1]);
 }
 
 OptionalLong max = Arrays.stream(windowTime).max();
 if (max.isPresent()) {
 long maxWindow = max.getAsLong();
 long minScore = currentTime - timeUnit.toMillis(maxWindow);
 
 redisUtils.removeRangeByScore(windowKey, 0, minScore - 1);
 }
 
 
 
 for (int i = 0; i < windowTime.length; i++) {
 
 long rangeBegin = currentTime - timeUnit.toMillis(windowTime[i]);
 
 Set<Object> limits = redisUtils.rangeByScore(windowKey, rangeBegin, currentTime);
 
 if (Objects.nonNull(limits)) {
 
 if (limits.size() < windowTimes[i]) {
 continue;
 }
 
 redisUtils.set(WINDOW_LIMIT + key, errorMsg, windowLimitTime[i], timeUnit);
 
 if (limits.size() > windowTimes[i]) {
 String[] errors = splitError(errorMsg);
 log.warn("当前[{}]被[{}]限制,锁定时间[{}],错误信息:[{}]", key, "窗口锁", redisUtils.getExpire(WINDOW_LIMIT + key), errors[0]);
 throw new ErrorCodeException(ErrorCodeEnum.ERROR, errors[1]);
 }
 }
 }
 
 redisUtils.zSetAdd(windowKey, StringUtils.replaceAll(UUID.randomUUID().toString(), "-", ""), currentTime);
 }
 
 | 
代码写的有点糙请谅解~
还是上面提到的小部分应用还是可以的,大规模的使用还是建议专业的事专业的人干比较好~