In high concurrency we often use traffic limiting to relieve the strain on the server. Redis traffic limiting is commonly used. There are many ways of Redis traffic limiting, and there are three common ways. These three ways can simply achieve traffic limiting.

Redis based on the setnx operation

When using Redis distributed lock, we all know that it relies on setNx instruction to set expiration time for the specified key during CAS operation. The main purpose of flow limiting is to ensure that only N requests per unit of time can access our program. So setNX can do that. For example, we need to limit 10 requests within 5 seconds, so we can set the expiration time to 5 during setNx, and the effect of limiting traffic will be achieved when the number of setNx requests reaches 10. The disadvantages of this approach are many. For example, when the statistics are 1 to 5 seconds, but they cannot be counted within 2 to 6 seconds. If M requests within N seconds need to be counted, then N keys need to be kept in Redis.

Data structure zset based on Redis

The most important aspect of limiting traffic is the sliding window, as mentioned above how 1 to 5 becomes 2 to 6. It’s just going to be +1 for both the starting value and the end value. The list data structure of Redis can easily implement this function. We can make requests into a Zset array, which can be generated with guIDS to keep value unique as each request comes in, and score can be represented with the current timestamp, because score can be used to count the number of requests within the current timestamp. The zset data structure also provides a range method that makes it easy to get the number of requests within the two timestamps. The code is as follows:

public Response limitFlow(a){
        Long currentTime = new Date().getTime();
        System.out.println(currentTime);
        if(redisTemplate.hasKey("limit")) {
            Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -  intervalTime, currentTime).size();
            System.out.println(count);
            if(count ! =null && count > 5) {
                return Response.ok("Maximum of 5 visits per minute");
            }
        }
        redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);
        return Response.ok("Access successful");
    }
Copy the code

With the above code, you can achieve the effect of sliding Windows and guarantee up to M requests every N seconds, but the disadvantage is that the data structure of zset gets bigger and bigger. The implementation is relatively simple.

Token bucket algorithm based on Redis

When it comes to limiting traffic, the token bucket algorithm has to be mentioned. The token bucket algorithm refers to the input rate and output rate. When the output rate is greater than the input rate, the traffic limit is exceeded. This means that every time we access a request, we can get a token from Redis. If we get a token, we are within the limit, and if we don’t get a token, we get the opposite result. With the above ideas, you can easily do this code with the Redis List data structure, just simple implementation. Rely on the leftPop of the List to get the token as follows:

public Response limitFlow2(Long id){
        Object result = redisTemplate.opsForList().leftPop("limit_list");
        if(result == null) {return Response.ok("No tokens in current token bucket");
        }
        return Response.ok(articleDescription2);
    }
Copy the code

Again, I rely on Java’s scheduled task to periodically push the token to the List. Of course, the token also needs to be unique, so I still use UUID to generate the token

	// rate of 10S Adds uuids to the token bucket to ensure uniqueness
    @Scheduled(fixedDelay = 10_000,initialDelay = 0)
    public void setIntervalTimeTask(a){
        redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
    }
Copy the code

The code implementation is not very difficult to start, for these methods of limiting the flow we can add the above code in AOP or filter, used to achieve interface limiting, ultimately protect your site.