【问题标题】:Tomcat7: Asynchronous Servlet not workingTomcat7:异步 Servlet 不工作
【发布时间】:2013-09-17 17:56:34
【问题描述】:

我已将 Tomcat7 配置为具有一个连接器线程,该线程将作业发布到后台线程池,这些线程池异步完成请求。每个请求都有 1 秒的延迟。我的测试(JMeter)启动了 5 个线程并同时发出 5 个请求。我期待单个连接器线程立即处理 5 个请求中的每一个。相反,它会等待上一个任务(在 bg 线程上运行)完成,然后再为下一个任务提供服务。

为了澄清,我的配置试图模仿像 Node.js 和 Tornado 这样的“单线程”异步服务器的线程架构。

连接器:

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           maxThreads="1"
           URIEncoding="UTF-8" />

Servlet:

@WebServlet(asyncSupported = true, value = "/testasync", loadOnStartup = 1)
public class TestAsync extends HttpServlet {
    private static final Logger LOG = Logger.getLogger(TestAsync.class.getName());
    private static final long serialVersionUID = 1L;
    private static final int NUM_WORKER_THREADS = 100;

private ExecutorService executor = null;

@Override
public void init() throws ServletException {
    this.executor = Executors.newFixedThreadPool(NUM_WORKER_THREADS);
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    final AsyncContext ac = request.startAsync(); // obtain async context
    ac.setTimeout(0); // test only, no timeout

    LOG.info("received request on: " + Thread.currentThread().getId());
    this.executor.execute(new Runnable() {
        public void run() {
            try {
                LOG.info("processing request: "+ Thread.currentThread().getId());
                Thread.sleep(5000);
                LOG.info("processed request:"+ Thread.currentThread().getId());
                ac.getResponse().getWriter().write("<h1>Request Processed</h1>");
                ac.complete();
            }
            catch (Exception e) {
                LOG.info("failed:" + e);
            }
        }
    });
    LOG.info("posted request on: " + Thread.currentThread().getId());
}

}

日志:

2013 年 9 月 17 日下午 12:26:00 TestAsync doGet INFO:收到请求:16

2013 年 9 月 17 日下午 12:26:00 TestAsync doGet INFO:发布请求于:16

2013 年 9 月 17 日下午 12:26:00 TestAsync$1 运行信息:处理请求:26

2013 年 9 月 17 日下午 12:26:05 TestAsync$1 运行信息:已处理请求:26

2013 年 9 月 17 日下午 12:26:05 TestAsync doGet INFO:收到请求:27

2013 年 9 月 17 日下午 12:26:05 TestAsync doGet INFO:发布请求:27

2013 年 9 月 17 日下午 12:26:05 TestAsync$1 运行信息:处理请求:28

2013 年 9 月 17 日下午 12:26:10 TestAsync$1 运行信息:已处理请求:28

2013 年 9 月 17 日下午 12:26:10 TestAsync doGet INFO:收到请求:27

2013 年 9 月 17 日下午 12:26:10 TestAsync doGet INFO:发布请求于:27

2013 年 9 月 17 日下午 12:26:10 TestAsync$1 运行信息:处理请求:29

2013 年 9 月 17 日下午 12:26:15 TestAsync$1 运行信息:已处理请求:29

2013 年 9 月 17 日下午 12:26:15 TestAsync doGet INFO:收到请求:27

2013 年 9 月 17 日下午 12:26:15 TestAsync doGet INFO:发布请求于:27

2013 年 9 月 17 日下午 12:26:15 TestAsync$1 运行信息:处理请求:30

2013 年 9 月 17 日下午 12:26:20 TestAsync$1 运行信息:已处理请求:30

2013 年 9 月 17 日下午 12:26:20 TestAsync doGet INFO:收到请求:27

2013 年 9 月 17 日下午 12:26:20 TestAsync doGet INFO:发布请求于:27

2013 年 9 月 17 日下午 12:26:20 TestAsync$1 运行信息:处理请求:31

2013 年 9 月 17 日下午 12:26:25 TestAsync$1 运行信息:已处理请求:31

【问题讨论】:

    标签: servlets tomcat7


    【解决方案1】:

    我相信这要归功于 Tomcat 中 BIO 连接器的使用。这是 Tomcat 安装中的默认连接器。 BIO connector blocks to read every request until the response is written 和池中的单个线程,您可以看到您描述的行为。

    如果您将maxThreads 增加到超过 1,您将看到其他线程接收传入请求,但连接器仍会阻止新连接,直到现有线程空闲。要移动到您想要的模型(当您想将处理委托给另一个时释放的单个请求线程),您需要切换到不阻塞的连接器(NIO 或 APR/Native)。您还可能需要增加线程池的大小(这实际上取决于请求处理线程是否只执行一项工作以及是否过载)。

    【讨论】:

    • 我认为Asynchronous Servlet的目的是将连接器线程池与处理线程池解耦,这样如果请求延迟较长,连接器线程就不会浪费(可以返回)。那么异步 Servlet 有什么好处呢?我的配置是为了模仿 Node.js 或 Tornado 等异步服务器的线程架构。
    • @lairtech 另请注意,Tomcat NIO 连接器会模拟阻塞,因此它的性能可能不如您预期的那样。 APR/Native 连接器可能会更好。
    • 我删除了对 JAX-RS 的依赖以隔离问题。使用 Http11NioProtocol 不起作用。这是我的配置:
    • 这很奇怪。请求处理肯定与线程 Id 的原始线程分离。但是通过处理每个请求之间的 5 秒延迟,看起来 (1) 原始线程没有立即返回到池中,或者 (2) 被阻止处理新请求(按设计)。 (1) 将是 Tomcat 中的一个错误,这不太可能。持久连接可能有助于 (2),因此您可能想查看关闭响应或不使用 keep-alive 是否有帮助。
    【解决方案2】:

    您应该使用 NIO 连接器和执行器池,如 here 所述。

    如果您没有真正充分的理由;没有理由用前面的一条线来限制你的自我。请查看我提供的网址。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-13
      相关资源
      最近更新 更多