我希望从社区中获得一些最佳实践指导。
今天,我帮助管理Java Web应用程序。我们使用Tomcat作为容器,总共有大约50个servlet。其中大多数是标准HttpServlet的扩展,尚未进行更新以利用Servlet 3.X规范的任何新asynchronous processing capabilities的优势。这些servlet支持UI通信,客户端设备通信等功能。
我们希望减轻的问题是,通过一个servlet的大量请求可能会使其他servlet饿死。这是两个方面。首先,大量的请求会消耗我们100%的系统资源,并使系统无响应。我们可以限制和调整这些请求,以使它们消耗更少的资源,但这通常会导致连接池堆积。无论哪种方式,我们最终都会遇到其他servlet没有响应的情况。
我们目前正在研究解决方案,其中包括利用Servlet 3.0的异步功能和线程池来支持应用程序的不同区域。首先,这将使我们能够更好地调整应用程序以适应不同类型的请求。其次,这将使我们能够评估请求的类型并相应地对其进行优先级排序。我们总是会有资源限制,至少这种方法使我们能够处理最重要的工作。
我们要讨论的一个理论难题是,在将所有内容转换为这种新方法之前(可能要花一段时间),传统的servlet和请求仍然会使应用程序饿死。
我对SO社区的具体问题是...
最后,我确实意识到,这在很大程度上是单个整体应用程序的副产品,该应用程序处理许多不同类型的请求。我们目前正在努力对应用程序进行模块化,并可能使我们达到可以在不同系统之间分发应用程序的地步。
谢谢!
答案 0 :(得分:1)
如果我可以提出一个不太合适的答案,则可以为不同的Executors赋予不同的优先级。
需要对其进行测试,以查看其好处是否是真实的和良好的,但是如果您负担得起两次运行该应用程序(由执行人员执行),这可能是一个临时解决方案。有罪的servlet将由最低优先级的执行程序处理,而其余的将由最高优先级的处理程序。
我看到了实现此问题的不同方法。通过更改web.xml以在应用程序1中隐藏servlet并转发到应用程序2,或通过实现filter来拦截对此有罪servlet的调用,然后将其发送到第二个应用程序。
答案 1 :(得分:0)
要限制每个servlet的请求,可以使用仅与特定servlet名称匹配的过滤器,并且仅允许同时处理特定数量的请求。
根据Servlet 2.5规范:
在部署描述符中,每个
<filter>
声明只有一个实例是 根据容器的JVM实例化
在过滤器内部,您可以使用Semaphore
来限制请求
ConcurrentRequestLimiter.java
private final int MAX_CONCURRENT_REQUESTS = 5;
private final Semaphore limiter = new Semaphore(MAX_CONCURRENT_REQUESTS);
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
try {
if (!limiter.tryAcquire(0, TimeUnit.SECONDS)) {
PrintWriter out = response.getWriter();
try {
out.print("System busy. Please try again later..");
} finally {
out.close();
}
}else{
try{
chain.doFilter(request, response);
}finally{
limiter.release();
}
}
} catch (InterruptedException ex) {/*Should never happen*/throw new ServletException("System inconsistency");}
}
web.xml
<filter>
<filter-name>ConcurrentRequestLimiter</filter-name>
<filter-class>ConcurrentRequestLimiter</filter-class>
</filter>
<filter-mapping>
<filter-name>ConcurrentRequestLimiter</filter-name>
<url-pattern>/FilteredRequest</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>FilteredRequest</servlet-name>
<servlet-class>FilteredRequest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FilteredRequest</servlet-name>
<url-pattern>/FilteredRequest</url-pattern>
</servlet-mapping>
注意:如果您希望对不同的servlet使用不同的阈值,则可以使用不同的别名多次声明该过滤器,并将num-concurrent-requests作为配置参数传递给它。