<p style="text-align: left;">This article mainly introduces the relevant knowledge of the method of Redis to realize the current limiter. The content is detailed and easy to understand, the operation is simple and fast, and has certain reference value. Which articles will be rewarding, let's take a look together.</p><p><br/></p><h3 style="text-align: left;">Method 1: Redis-based setnx operation</h3><p style="text-align: left;">When we use Redis distributed locks, we all know that we rely on setnx instructions , during the operation of CAS (Compare and swap), at the same time set the expiration practice (expire) for the specified key, the main purpose of our current limit is to have and only N number of requests can access within a unit time My code program. So relying on setnx can easily do this function.</p><p style="text-align: left;">For example, we need to limit 20 requests within 10 seconds, then we can set the expiration time to 10 when setnx, and when the number of setnx requests reaches 20, the current limiting effect is achieved. The code is relatively simple and will not be displayed.</p><p style="text-align: left;">Of course, there are many disadvantages of this approach. For example, when counting 1-10 seconds, it is impossible to count within 2-11 seconds. If we need to count M requests within N seconds, then our Redis needs to keep N keys and so on.</p><p style="text-align: left;">In the specific implementation, you can consider using the interceptor HandlerInterceptor:</p><pre class="brush:csharp; hljs java" style="margin-top: 8px; margin-bottom: 8px; padding: 15px; box-sizing: border-box; overflow-x: auto; background-color: rgb(240, 242, 245); color: rgb(45, 48, 55); font-size: 14px; border: 1px solid rgb(219, 225, 232); border-radius: 4px; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-all; text-align: left;">public class RequestCountInterceptor implements HandlerInterceptor {
private LimitPolicy limitPolicy;
public RequestCountInterceptor(LimitPolicy limitPolicy) {
this.limitPolicy = limitPolicy;
}
@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!limitPolicy.canDo()) {
return false;
}
return true;
}
}</pre><p style="text-align: left;">At the same time add a configuration LimitConfiguration:</p><pre class="brush:csharp; hljs java" style="margin-top: 8px; margin-bottom: 8px; padding: 15px; box-sizing: border-box; overflow-x: auto; background-color: rgb(240, 242, 245); color: rgb(45, 48, 55); font-size: 14px; border: 1px solid rgb(219, 225, 232); border-radius: 4px; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-all; text-align: left;">@Configurationpublic class LimitConfiguration implements WebMvcConfigurer {
@Override public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RequestCountInterceptor(new RedisLimit1())).addPathPatterns("/my/increase");
}
}</pre><p style="text-align: left;">In this way, each time before the /my/increase request reaches the Controller, the current limit is carried out according to the policy RedisLimit1, and the code in the original Controller does not need to be modified:</p><pre class="brush:csharp; hljs java" style="margin-top: 8px; margin-bottom: 8px; padding: 15px; box-sizing: border-box; overflow-x: auto; background-color: rgb(240, 242, 245); color: rgb(45, 48, 55); font-size: 14px; border: 1px solid rgb(219, 225, 232); border-radius: 4px; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-all; text-align: left;">@RestController@RequestMapping("my")public class MyController {
int i = 0;
@RequestMapping("/increase")
public int increase() {
return i++;
}
}</pre><p style="text-align: left;">The specific current limiting logic code is in the RedisLimit1 class:</p><pre class="brush:csharp; hljs java" style="margin-top: 8px; margin-bottom: 8px; padding: 15px; box-sizing: border-box; overflow-x: auto; background-color: rgb(240, 242, 245); color: rgb(45, 48, 55); font-size: 14px; border: 1px solid rgb(219, 225, 232); border-radius: 4px; white-space: pre-wrap; overflow-wrap: break-word; word-break: break-all; text-align: left;">/**
* Method 1: Redis-based setnx operation
*/public class RedisLimit1 extends LimitPolicy {
static {
setNxExpire();
}
private static boolean setNxExpire() {
SetParams setParams = new SetParams();
setParams.nx();
setParams.px(TIME);
String result = jedis.set(KEY, COUNT + "", setParams);
if (SUCCESS.equals(result)) {
return true;
}
return false;
}
@Override public boolean canDo() {
if (setNxExpire()) {
// return true;
} else {
// return jedis.decrBy(KEY, 1) > 0;
}
}
}public abstract class LimitPolicy {
public static final int COUNT = 10; //10 request public static final int TIME= 10*1000 ; // 10s public static final String SUCCESS = "OK";
static Jedis jedis = new Jedis();
abstract boolean canDo();
}</pre><p style="text-align: left;">One effect achieved in this way is a maximum of 10 requests per second.</p>