我得到了这个servlet,它将pdf文件返回给客户端Web浏览器。 我们不想冒任何风险,当请求数量过多时,服务器就会瘫痪。
我们希望以应用程序级别(程序)的方式设置并发请求数量的限制,并在达到限制时向浏览器返回错误消息。我们需要在应用程序级别执行它,因为我们在开发级别(tomcat)和生产级别(websphere)中有不同的servlet容器。
我必须强调,我想控制最大请求数而不是会话数。用户可以使用相同的会话通过服务器发送多个请求。
有什么想法吗? 我曾考虑使用静态计数器来跟踪请求的数量,但这会引起竞争条件的问题。
答案 0 :(得分:19)
我建议编写一个简单的servlet Filter
。在web.xml
中对其进行配置,以应用于要限制并发请求数的路径。代码看起来像这样:
public class LimitFilter implements Filter {
private int limit = 5;
private int count;
private Object lock = new Object();
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
boolean ok;
synchronized (lock) {
ok = count++ < limit;
}
if (ok) {
// let the request through and process as usual
chain.doFilter(request, response);
} else {
// handle limit case, e.g. return status code 429 (Too Many Requests)
// see http://tools.ietf.org/html/rfc6585#page-3
}
} finally {
synchronized (lock) {
count--;
}
}
}
}
或者您也可以将此逻辑放入HttpServlet
。它只是更清洁,更可重复使用Filter
。您可能希望通过web.xml
配置限制,而不是对其进行硬编码。
<强>参考:强>
检查HTTP status code 429的定义。
答案 1 :(得分:2)
我考虑使用静态计数器来跟踪请求的数量,但这会引起竞争条件的问题。
如果您使用AtomicInteger作为计数器,您将不会遇到竞争条件的问题。
另一种方法是使用Java Executor Framework(Java 1.5附带)。在那里你可以限制正在运行的线程的数量,并阻止新的一次,直到有一个新的免费线程。
但我认为计数器可行并且是最简单的解决方案。
注意:将计数器放在最后一个块中!
//psydo code
final AtomicInteger counter;
...
while(true) {
int v = counter.getValue()
if (v > max) return FAILURE;
if(counter.compareAndSet(v, v+1)) break;
}
try{
doStuff();
} finally{
counter.decrementAndGet();
}
答案 2 :(得分:2)
答案 3 :(得分:2)
您可以使用RateLimiter。有关解释,请参阅this文章。
答案 4 :(得分:0)
如果您正在提供静态文件,则服务器不太可能崩溃。瓶颈将是网络吞吐量,并且它会优雅地降级 - 当有更多请求进入时,每个请求仍会得到服务,只是稍微慢一些。
如果您对总请求设置了硬限制,请记住设置每个IP请求的限制。否则,一个坏人很容易发出N个请求,故意非常慢地阅读响应,并完全阻塞你的服务。即使他在拨号上并且您的服务器网络具有巨大的吞吐量,这也可以工作。