每个Servlet管理Tomcat请求

时间:2018-06-21 17:17:53

标签: java performance tomcat servlets

我希望从社区中获得一些最佳实践指导。

今天,我帮助管理Java Web应用程序。我们使用Tomcat作为容器,总共有大约50个servlet。其中大多数是标准HttpServlet的扩展,尚未进行更新以利用Servlet 3.X规范的任何新asynchronous processing capabilities的优势。这些servlet支持UI通信,客户端设备通信等功能。

我们希望减轻的问题是,通过一个servlet的大量请求可能会使其他servlet饿死。这是两个方面。首先,大量的请求会消耗我们100%的系统资源,并使系统无响应。我们可以限制和调整这些请求,以使它们消耗更少的资源,但这通常会导致连接池堆积。无论哪种方式,我们最终都会遇到其他servlet没有响应的情况。

我们目前正在研究解决方案,其中包括利用Servlet 3.0的异步功能和线程池来支持应用程序的不同区域。首先,这将使我们能够更好地调整应用程序以适应不同类型的请求。其次,这将使我们能够评估请求的类型并相应地对其进行优先级排序。我们总是会有资源限制,至少这种方法使我们能够处理最重要的工作。

我们要讨论的一个理论难题是,在将所有内容转换为这种新方法之前(可能要花一段时间),传统的servlet和请求仍然会使应用程序饿死。

我对SO社区的具体问题是...

  1. 在努力实现这一机制的同时,有什么方法可以限制每个servlet的请求以防止饱和?
  2. 是否有关于“最佳做法”这类转化的资源?
  3. 我们想要的状态有什么陷阱吗?如果是这样,您需要什么建议来缓解它们?

最后,我确实意识到,这在很大程度上是单个整体应用程序的副产品,该应用程序处理许多不同类型的请求。我们目前正在努力对应用程序进行模块化,并可能使我们达到可以在不同系统之间分发应用程序的地步。

谢谢!

2 个答案:

答案 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作为配置参数传递给它。