限流之滑动窗口算法的实现

计数器滑动窗口的出现,就是为了解决计数器限流方式中在窗口切换时产生2倍于阈值的缺点。

原理

滑动窗口是在计数器限流的固定窗口的基础上,把固定窗口划分为多个小窗口,这些小窗口构成一个环,每个小窗口分别计数,而这些小窗口计数的总和不能超过中的限制,从而保证限流。

同时当请求的时间大于当前窗口的最大值时,进行调整滑动窗口,把滑动窗口先后移动一个或多个小窗口(滑动多少取决于请求时间超过了多个少窗口时间),同时把滑动的窗口计数清空。

从上图可以看到,划分小窗口数量越多,限流则越准确。由于小窗口计数的总和不能超过最大限度,保证了时间轴中每个时间片过程中不会出现限流的最大限度。当然,若不进行小窗口划分,计数器滑动窗口限流也就退化成了计数器固定窗口。

实现

#include <stdio.h>
#include  <stdlib.h>
#include <time.h>
#include <sys/time.h> 
#include <unistd.h>


long max(long a, long b)
{
    return a>b ? a: b;
}

long  min(long a, long b)
{
    return a>b ? b : a; 
}


int gwindowSize; //窗口大小,毫秒为单位
int glimit;//窗口内限流大小
int gsplitNum;//切分小窗口的数目大小
int * counters;//每个小窗口的计数数组
int gindex;//当前小窗口计数器的索引
long startTime;//窗口开始时间


long getCurrentTime()
{
    struct timeval stTimeVal;
    struct tm *pstTimeCurrent = NULL;


    gettimeofday(&stTimeVal, NULL);
    pstTimeCurrent = localtime((time_t *)&stTimeVal.tv_sec);

    return mktime(pstTimeCurrent);  

}


void init(int windowSize, int limit, int splitNum)
{
    gwindowSize = windowSize;
    glimit = limit;
    gsplitNum = splitNum;
    counters = (int *)calloc(splitNum , sizeof(int));
    gindex = 0;
    startTime = getCurrentTime();

    return;
}

//把已经超时的小窗口对应的数组置0,也即是进行滑动窗口
void slideWindow(int windowsNum)
{
    if(windowsNum == 0)
        return ;

    //最大也就是把所有的数组清空
    int slideNum = min(windowsNum, gsplitNum);

    for(int i=0; i<slideNum; i++)
    {
        gindex = (gindex + 1) % gsplitNum;
        counters[gindex] = 0;
    }   

    startTime = startTime + windowsNum * (gwindowSize / gsplitNum);

    return ;
}


int IsValid() 
{
    long now = getCurrentTime();

    //获取开始时间至当前时间经过了多少小窗口
    int windowsNum = (int)(max(now - startTime - gwindowSize, 0) / (gwindowSize / gsplitNum)); //windowSize / splitNum 表示每个小窗口多长时间

    slideWindow(windowsNum); //滑动窗口

    int count = 0; //记录当前所有窗口处理的数量

    //统计从startTime 到 now这段时间共处理了多少请求
    for(int i=0; i < gsplitNum; i++)
    {
      count += counters[i];
    }


    //超过限制则限流
    if(count >= glimit)
        return 0;
    else //未超限则处理
    {
        counters[gindex]++;
        return 1;
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值