how to count number of requests in last second, minute and hour

后端 未结 10 1902
情歌与酒
情歌与酒 2020-12-07 09:35

There is a hypothetical web server which supports only one very simple API - count of requests received in the last hour, minute and second. This server is very popular in t

相关标签:
10条回答
  • 2020-12-07 10:27

    My solution :

    1. Maintain a hash of 3600 ,which contains a count,timestamp as fields.

    2. For each request for:

      • get idx(index in arry for current element) by timestamp%3600.
      • if hash[idx].count=0, then hash[idx].count=1 and hash[idx].timestamp=inputTimeStamp
      • if hash[idx].count>0 ,then

      Case(1) : if i/p timestamp==hash[idx].timestamp,hash[count]++;

      Case(2) : if i/p timestamp>hash[idx].timestamp,then hash[idx].count=1 and hash[idx].timestamp=inputTimeStamp

      Case(3): : if i/p timestamp<hash[idx].count // old request, can be ignored.

    Now for any query for last second,minute,hour: Find idx as above, and as long as the timestamp matches with in given second/range/minute,keep on iterating back from from idx in circular manner.

    0 讨论(0)
  • 2020-12-07 10:29

    Why not just use a circular array? We have 3600 elements in that array.

    index = 0;
    Array[index % 3600] = count_in_one_second. 
    ++index;
    

    if you want last second, return the last element of this array. if you want last minute, return the sum of last 60 elements. if you want last hour, return the sum of the whole array (3600 elements).

    Isn't his a simple and effective solution?

    Thanks

    Deryk

    0 讨论(0)
  • 2020-12-07 10:33

    I had to solve this problem in Go, and I don't think I saw this approach yet, but it may also be very specific to my use case.

    Since it is connecting to a 3rd party API and needs to limit its own requests, I simply kept a counter for the last second and a counter for the last 2 minutes (the two counters I needed)

    var callsSinceLastSecond, callsSinceLast2Minutes uint64
    

    Then I'd launch my requests in separate go routines when the calls counters were below my allowable limit

    for callsSinceLastSecond > 20 || callsSinceLast2Minutes > 100 {
        time.Sleep(10 * time.Millisecond)
    }
    

    And at the end of each go routine I would atomically decrement the counter.

    go func() {
        time.Sleep(1 * time.Second)
        atomic.AddUint64(&callsSinceLastSecond, ^uint64(0))
    }()
    
    go func() {
        time.Sleep(2 * time.Minute)
        atomic.AddUint64(&callsSinceLast2Minutes, ^uint64(0))
    }()
    

    And that seems to work so far without any issue with some pretty heavy testing so far.

    0 讨论(0)
  • 2020-12-07 10:35

    What about a simple list of timestamps? Each time you're making a request you append the current timestamp to the list. And each time you want to check if you're under the rate limit, you first remove timestamps older than 1 hour to prevent stack overflow (hehe) then you count the number of timestamps in the last second, minute, whatever.

    It could be done easily in Python:

    import time
    
    requestsTimestamps = []
    
    def add_request():
        requestsTimestamps.append(time.time())
    
    def requestsCount(delayInSeconds):
        requestsTimestamps = [t for t in requestsTimestamps if t >= time.time() - 3600]
        return len([t for t in requestsTimestamps if t >= time.time() - delayInSeconds])
    

    I guess this can be optimized but you see the idea.

    0 讨论(0)
提交回复
热议问题