赞
踩
使用固定窗口实现限流的思路大致为,将某一个时间段当做一个窗口,在这个窗口内存在一个计数器记录这个窗口接收请求的次数,每接收一次请求便让这个计数器的值加一,如果计数器的值大于请求阈值的时候,即开始限流。当这个时间段结束后,会初始化窗口的计数器数据,相当于重新开了一个窗口重新监控请求次数。
- package com.example.demo;
-
- import java.util.Date;
-
- public class FixedWindow {
-
- private long time = new Date().getTime();
-
- private Integer count = 0; // 计数器
-
- private final Integer max = 100; // 请求阈值
-
- private final Integer interval = 1000; // 窗口大小
-
- public boolean trafficMonitoring() {
-
- long nowTime = new Date().getTime();
-
- if (nowTime < time + interval) {
- // 在时间窗口内
- count++;
-
- return max > count;
-
- } else {
- time = nowTime; // 开启新的窗口
-
- count = 1; // 初始化计数器,由于这个请求属于当前新开的窗口,所以记录这个请求
-
- return true;
- }
- }
-
- }
由上面的代码我们可以看出,固定窗口可以对一段时间的流量就行监控,但是有一个致命的问题,就是我们监控流量都是指时间段而不是具体的某一个时间,假设我们的窗口时间为一分钟,当一分钟后会切换到另外一个窗口重新监控。这个切换就有可能出现问题。假设我们在第一个窗口的最后十秒发了100个请求,在第二个窗口开始的时候也可以发100个请求,那么在这二十秒时间内服务器就会接收到200个请求,这样很有可能会使服务器接收的请求过多而挂掉。所以就出现了固定窗口的优化版,滑动窗口来解决这个问题。
滑动窗口为固定窗口的改良版,解决了固定窗口在窗口切换时会受到两倍于阈值数量的请求,滑动窗口在固定窗口的基础上,将一个窗口分为若干个等份的小窗口,每个小窗口对应不同的时间点,拥有独立的计数器,当请求的时间点大于当前窗口的最大时间点时,则将窗口向前平移一个小窗口(将第一个小窗口的数据舍弃,第二个小窗口变成第一个小窗口,当前请求放在最后一个小窗口),整个窗口的所有请求数相加不能大于阀值。
由上图我们可以看出每次窗口只是做了平移,舍弃第一个窗口,将最新的请求放置到最后的窗口,这样就保证了这滑动窗口的时间内对流量的监控。
java代码实现如下:
- package com.example.demo;
-
- import java.util.Date;
-
- public class SlidingWindow {
-
- private long[][] arr = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };
-
- private final int max = 100;
-
- private long size = 600000;// 窗口大小
-
- private long time = new Date().getTime();// 窗口开始时间
-
- public boolean trafficMonitoring() {
-
- long nowTime = new Date().getTime();// 请求进来的时间
-
- // 计算坐标
- long result = (nowTime - time) % 10000;
-
- int index = 0;
-
- if (result == 0) {
- index = (int) (nowTime / time);
- } else {
-
- index = (int) (nowTime / time + 1);
- }
-
- if (index > arr.length) {
- // 不在窗口内,将滑动窗口平移
- for (int i = 0; i < index - arr.length; i++) {
- // 将数组平移
- for (int j = 0; j < arr.length - 1; j++) {
-
- arr[j][0] = arr[j + 1][0];
- }
- // 将起始时间也向前推进一个窗口
- time += 10000;
- }
- // 本次插入的窗口为最后一个窗口
- index = arr.length - 1;
- }
- // 计算窗口总的请求数是否小于阈值
- int total = 0;
- for (int i = 0; i < arr.length; i++) {
- total += arr[i][0];
- }
- if (total > max) {
- return false;
- }
- // 获取小窗口目前的请求值
- long count = arr[index - 1][0];
- // 加上本次请求数
- arr[index - 1][0] = count + 1;
-
- return true;
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。