如何判断1分钟内请求次数在20次之内

自己考虑的算法是这样的,先取当前时间记为startTime,然后请求判断部分,对于第一个请求判断当前时间-startTime是否小于1分钟,如果小于1分钟则请求计数加1,第二个请求判断当前时间-startTime是否小于1分钟。。。。(这里的startTime我设为static Date startTime = new Date();但是每次都会将初始的给定时间设为当前时间,这个怎样能让startTime保持为静态时间变量,当时间到达1分钟后再更新他为当前时间那)有没有大侠遇到过?

j_clxy
clxy大叔 虽然你已经采纳了,但是请允许我再唠叨下。 你下面贴出做法是不够严谨的。 比如我贴出例子 [quote]比如第1分10秒1次,第1分59秒19次,第2分20秒再1次时如何?[/quote] 按照你的算法,第2分20秒的这次会被做为过多请求而被拒绝。 但是实际上,在距离这次请求的1分钟以内只有20次,应该作为合法请求。 你可以再想想。
6 年多之前 回复
chop123
chop123 感谢亲的回复!搞定了,我用的比较简单的设了一个static静态变量记录时间和static静态变量记录次数,并且用到了synchronized对static变量进行更新操作,感谢亲的回答用synchronized真的解决了问题!也感谢其他同学的回答~~
6 年多之前 回复

10个回答

首先,这个处理应该是IP地址级别或session级别的。就是说每个IP地址或每个session做此限制。所以你这个时间设成static即jvm级别的,恐怕不大对头吧?

我的计算逻辑是这样的:

1.每个IP或session维护个访问时间的列表。
2.每次该IP或session有访问时,取当前时间,然后减去1分钟。
3.删除【1】中的列表里,所有小于【2】的时间的数据。
4.a. 如果【3】处理后的列表个数小于20,允许访问,添加本次访问时间。
4.b. 如果大于等于20,拒绝访问。

但是,除非这是你们已经规定好的逻辑。
否则,通常的限制是,刷新间隔不得小于某固定时间(比如1秒或几秒)。

逻辑就会简单多了,像你上面那样,只需要个上次访问时间即可。
但还得是IP地址或session级别的才对。

chop123
chop123 是web开发的 呵呵 我再想想怎么处理
6 年多之前 回复
j_clxy
clxy大叔 我想当然的认为是web开发,所以提到了同步。 如果不是web或者没有并发,那是不用考虑同步这些事情。 如果是,则需要同步。简单些的话,需要用static变量做锁,比如 [code="java"] synchronized (static变量) { //处理 } [/code] 再来说你的方法,我认为逻辑不对,实现不了需求。 你可以自己多造些模拟数据,不要只有初始的数据。 比如第1分10秒1次,第1分59秒19次,第2分20秒再1次时如何?
6 年多之前 回复
chop123
chop123 谢谢您的回复。你说的session处理的是么?我还没接触过,刚开始做java开发,我写的很简单的不知道行不行得通: public class Check{ private static Date startTime = new Date();//初始时间先是当前系统时间 private static long temp;//临时记录请求次数 public void execute() throws Exception{ Date now = new Date(); if(now.getTime()-startTime().getTime<=6000 && temp<=20)//如果当前时间距离初始时间在1分钟内且请求次数小于20次 temp++;//计数加1 else{ startTime = new Date();//重置startTime为当前系统时间 temp=0;//临时计数清0 return; } } 自己想的就是这种比较笨的办法,不知道系统并发请求这个接口时有没有问题?
6 年多之前 回复
j_clxy
clxy大叔 记得要同步。
6 年多之前 回复
j_clxy
clxy大叔 如果需求是针对整个系统的,即系统在1分钟内只允许N次的话,那么用static倒也没问题。 你的算法看上去实在不够清晰,而且只有一个startTime应该是实现不了的。 还请参考我的逻辑吧。 也就是,维护一个static的列表,每次有访问来的时候按照上面的逻辑,从【2】开始处理就OK了。
6 年多之前 回复
chop123
chop123 非常感谢您的回复!其实我不清楚这样的需求的实现方式,我自己简单写的能否满足。需求是不需要对IP做限制的,只是对请求次数做限制,1分钟内运行访问20次,前端用http请求,后端json格式返回的,不知道你说的session是咋样来实现的?能否说明下下
6 年多之前 回复

自己写个filter,拦截所有的请求
再启动个线程或者timer什么的,1分钟重置一次
要注意的是filter是两次的

是单例吗?

保证单例,然后需要起一个线程去维护静态startTime,每个1000ms,重置startTime为当前系统时间。

楼主的提问有点不知所云啊,楼主是想统计每分钟请求不超过20个么?如果某分钟请求了19个,但都集中在最后一秒,下一分钟也请求了19个,但都集中在第一秒,岂不是2秒就请求了38个了?楼主的统计方式不太对吧?或者楼主只是想维持一个一分钟刷新一次的对象?

每个IP对应一个队列(FIFO)队列长度为20,队列中保存访问时间

如果
队头 - 队尾 > 60秒 说明请求太频繁了

ieanwfg201
ieanwfg201 我觉得使用循环链表比较好点,队列的话涉及到移位,比较耗费性能。
6 年多之前 回复
xly_971223
xly_971223 说反了, 队头 - 队尾 < 60秒, 命中
6 年多之前 回复

tcp、ip有个时间滑动窗口,不知道有没有可以借鉴的地方?其实Esper应该有相关的实现,可以参考。

作者问题提的有点模糊,我可以这样理解 吗?就是保持任何时间段(一分钟)内的请求数小于20。如果是这样的话,我们可以创建一个SIZE为20的容器(队列)。元素为time+data,也就是你说的请求。每次往里插入的时候,判断一下容器中元素的time是在一分钟之内的就可以了。如果队首的元素time在一分钟之内,队列已满(20个),刚说明一分种之内的请求已大于20了。

我觉得用queue比较好

请问你是不是需要一个这样的程序?
[code="java"]
/**

  • @author John zhang
  • @version 1.0
    */
    public class RequestOutOf20 {

    static Date startTime = new Date();
    static long ONE_MINUTE = 1 * 60 * 1000L;

    int requestCounter = 0;
    int timeCounter = 1;

    void request() {
    long curTime = System.currentTimeMillis();
    if (curTime - startTime.getTime() > ONE_MINUTE) {
    System.out.println(String.format("第%s分钟请求为%s次", timeCounter, requestCounter));
    String msg = (requestCounter > 20) ? "已超过20次": "未超过20次";
    System.out.println(msg);
    timeCounter++;
    requestCounter = 0;
    startTime = new Date();
    return;
    }
    requestCounter++;
    }

    public static void main(String args[]) {
    RequestOutOf20 req = new RequestOutOf20();
    for(int i = 0; i < 200000; i++) {
    req.request();
    Random r = new Random();
    int interval = r.nextInt(10) * 1000;
    System.out.println(String.format("间隔时间为%s秒", interval));
    try {
    Thread.sleep(interval);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    }
    }
    [/code]

z276356445t
z276356445t 我以为你只是需要一个怎么去计算的程序, 而且在不同的场景下选择的用法也不同, 我只是提供给你一个思路.
6 年多之前 回复
chop123
chop123 如果用于web开发要支持多线程访问的话,还是得用synchronized的吧,亲!
6 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!