使用redisson限流器Ratelimiter实现限流,保证服务正常可用
使用的jar包:
implementation 'org.redisson:redisson-spring-boot-starter:3.13.6'
定义自定义注解
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.springframework.web.bind.annotation.Mapping;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestRateLimiter {
String key();
RateType type() default RateType.PER_CLIENT;
long rate() default 10;
long rateInterval() default 1000;
RateIntervalUnit timeUnit() default RateIntervalUnit.MILLISECONDS;
}
定义AOP切面
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@Aspect
@Component
public class RequestRateLimitAspect {
@Autowired
private RedissonClient redisson;
@Pointcut("@annotation(requestRateLimiter)")
public void accessLimit(RequestRateLimiter requestRateLimiter) {
}
@Around(value = "accessLimit(requestRateLimiter)", argNames = "pjp,requestRateLimiter")
public Object around(ProceedingJoinPoint pjp, RequestRateLimiter requestRateLimiter) throws Throwable {
RRateLimiter rRateLimiter = getRateLimiter(requestRateLimiter);
if (rRateLimiter.tryAcquire(1)) {
return pjp.proceed();
} else {
return buildErrorResult();
}
}
private RRateLimiter getRateLimiter(RequestRateLimiter requestRateLimiter){
RRateLimiter rRateLimiter = redisson.getRateLimiter(StringUtils.isBlank(requestRateLimiter.key()) ? "default:limiter" : requestRateLimiter.key());
if(rRateLimiter.isExists()) {
RateLimiterConfig rateLimiterConfig = rRateLimiter.getConfig();
if (!Objects.equals(requestRateLimiter.rate(), rateLimiterConfig.getRate())
|| !Objects.equals(requestRateLimiter.timeUnit().toMillis(requestRateLimiter.rateInterval()), rateLimiterConfig.getRateInterval())
|| !Objects.equals(requestRateLimiter.type(), rateLimiterConfig.getRateType())) {
rRateLimiter.delete();
rRateLimiter.trySetRate(requestRateLimiter.type(), requestRateLimiter.rate(), requestRateLimiter.rateInterval(), requestRateLimiter.timeUnit());
}
} else {
rRateLimiter.trySetRate(requestRateLimiter.type(), requestRateLimiter.rate(), requestRateLimiter.rateInterval(), requestRateLimiter.timeUnit());
}
return rRateLimiter;
}
public Object buildErrorResult() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("code", "-1");
map.put("message", "Too many people visit");
return map;
}
}
定义url请求:
import org.redisson.api.RateIntervalUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/redis/test")
public class RedisController {
private final Logger logger = LoggerFactory.getLogger(RedisController.class);
@Autowired
private RedisService redisService;
@RequestMapping("/add")
@RequestRateLimiter(key = "test", rate = 1, rateInterval = 2, timeUnit = RateIntervalUnit.SECONDS)
public Object add(String data) {
logger.info("进入请求");
redisService.add("testkey", data);
return "成功";
}
}
jmeter压测配置:
jmeter压测结果:
在声明的上述自定义注解和AOP切面之后,只需要在需要使用限流的请求方法上声明对应的自定义注解及参数配置即可实现限流。
|