我的要求是,
我有一个REST API,它接受请求参数,从这个请求我们获得appId,userid和IP地址(来自的请求)我需要对每秒5个请求进行速率限制(对于给定的密钥)组合)。
我有这个示例代码限制用户允许最多5个请求/秒。当只有一个用户发送超过5个请求时,它工作正常,它只允许5个请求/秒,而对于剩余请求,它会抛出错误"请求太多"。但是当有多个用户(比如5个)并且每个用户发送超过5个请求/秒时,则无法限制用户的费率(这里所有5个用户应该能够发送5个请求/秒)即,总共25个请求应该是成功的,剩下的请求应该抛出错误,例如"太多的请求"。 请告诉我我失踪的地方。
import java.util.concurrent.ConcurrentMap;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
@Controller
public class HomeController {
private int CACHESIZE = 1000;
private int rateRequests = 5;
private ConcurrentMap<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(CACHESIZE).build().asMap();
private RateLimiter rateLimiter;
HomeController() {
rateLimiter = RateLimiter.create(rateRequests);
}
@RequestMapping(value = "/getData", method = RequestMethod.GET)
public String getData(HttpServletRequest request) {
if (!preCheck(request)) {
return null;
} else {
return "get userdata from data base";
}
}
private boolean preCheck(HttpServletRequest request) {
String key = request.getParameter("userId") + request.getParameter("applicationId") + request.getRemoteAddr();
RateLimiter rateLimiter = getRateLimiter();
if (cache.containsKey(key)) {
rateLimiter = (RateLimiter) cache.get(key);
} else {
cache.put(key, rateLimiter);
}
boolean allow = rateLimiter.tryAcquire();
if (!allow) {
System.out.println("Too many request");
}
return allow;
}
public RateLimiter getRateLimiter() {
return rateLimiter;
}
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class RateLimitTest {
public static void main(String[] args) {
RateLimitTest limitTest = new RateLimitTest();
limitTest.scheduleJob();
}
static ExecutorService executorService = Executors.newFixedThreadPool(10);
private void scheduleJob() {
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
executorService.submit(new Runnable() {
@Override
public void run() {
// getUserData("user1");
getUserData(randomGen(5));
}
});
}
}
}, 0, 20, TimeUnit.SECONDS);
}
private String randomGen(int count) {
String value = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder builder = new StringBuilder();
while (count-- != 0) {
int charIndex = (int) (Math.random() * value.length());
builder.append(value.charAt(charIndex));
}
return builder.toString();
}
private String getUserData(String user) {
return "call rest api( /getData ) to get the user data";
}
}
答案 0 :(得分:0)
我认为这是因为所有请求共享一个速率限制器,因此您应该为每个密钥创建一个速率限制器。试试这个:
private boolean preCheck(HttpServletRequest request) {
String key = request.getParameter("userId") + request.getParameter("applicationId") + request.getRemoteAddr();
RateLimiter rl = cache.get(key);
if(rl == null){
rl = RateLimiter.create(rateRequests);
RateLimiter old = cache.putIfAbsent(key , rl);
if(old !=null){
rl = old;
}
}
boolean allow = rl.tryAcquire();
if (!allow) {
System.out.println("Too many request");
}
return allow;
}
不要忘记删除属性 rateLimiter
的定义