多用户同时访问的 Web 应用程序的 ExecutorService 线程池大小

Posted

技术标签:

【中文标题】多用户同时访问的 Web 应用程序的 ExecutorService 线程池大小【英文标题】:ExecutorService thread-pool size for web application accessed concurrently by multiple users 【发布时间】:2018-05-10 02:48:43 【问题描述】:

我们在 tomcat 中部署了一个 Java Web 服务应用程序。服务器是 3 核和 7GB RAM。 它在具有自动缩放功能的云中启用了多达 20 个实例。 在任何给定时间点,至少 1000 名用户将同时访问此 Web 服务。

现在来到Web服务代码,它需要并行处理15个不同的方法(每个方法平均需要3秒),等待所有方法返回响应,处理所有响应并返回输出到调用客户端。我们同样使用带有 FixedThreadPool 的 Java Executor Service。

问题:

    在 Servlet init() 方法中启动 FixedThreadPool Executor 并在 servlet 销毁时将其关闭以便线程池初始化一次并且应用程序使用此池中的线程是个好主意吗

    固定线程池大小应该是多少?它应该是 1k 或 2k 范围内的一个非常高的数字,因为有多个客户端同时调用 Web 服务?还是应该是一个较小的数字?我们应该如何想出一个线程池大小,以便所有 1000 个访问 Web 服务的客户端都能立即获得响应。

    我们是否应该为我们的场景使用缓存线程池而不担心池大小?

请帮助。

【问题讨论】:

【参考方案1】:

在 Servlet init() 方法中启动 FixedThreadPool Executor 并在 servlet 销毁时将其关闭是否是个好主意,以便线程池初始化一次并且应用程序使用该池中的线程

你当然可以这样做,但更典型的做法是初始化一个全局线程池,然后让每个请求共享同一个池。如果优化池中的线程数(见下文),如果每个请求都有自己的池,则很难协调并行执行的请求。

也就是说,如果您需要派生多个线程然后等待它们完成,则每个请求使用一个池可能会更容易——尤其是如果这些请求需要很长时间才能运行,这意味着池的创建是整体工作的一小部分。

固定线程池大小应该是多少?

如果没有关于相关工作的更多信息,这是一个很难回答的问题。如果请求非常受 IO 限制,通常会增加线程数——例如等待网络连接。 1-2k 线程可能会工作,但如果目标是排队 none 的作业,那么我当然会使用缓存线程池。

如果您要最大化服务器的 CPU,那么您应该减少线程数,因为您可能同时运行太多作业,这可能会降低您的整体吞吐量。如果所有 15 个作业必须同时运行,也应考虑到这一点。

我们应该如何得出一个线程池大小,以便所有 1000 个访问 Web 服务的客户端都可以不延迟或等待返回响应。

仅仅添加更多线程并不一定会让事情变得更快。这与吞吐量有关。如果可能的话,您应该对您的请求进行建模,或者在生产环境中尝试一些设置,然后比较每秒请求数等,以确定哪些线程池设置会产生最高的总体吞吐量。

我们是否应该为我们的场景使用缓存线程池而不担心池大小?

您当然可以,但是您担心的是请求数量会增加,这会导致启动大量线程。同样,将有一个最佳数量的线程在服务器中运行并处理请求。线程过多不会使作业更快完成,而且由于它们占用资源并增加上下文切换频率,很容易降低整体吞吐量。

【讨论】:

抱歉延迟回复。感谢您的详细解释。将尝试建议的方法,看看哪种方法更适合我们的情况。谢谢!

以上是关于多用户同时访问的 Web 应用程序的 ExecutorService 线程池大小的主要内容,如果未能解决你的问题,请参考以下文章

如何设计一个多用户 ajax Web 应用程序以保证并发安全

Python静态Web服务器-多任务版

当一个 MVC Web 应用程序托管在多个用户同时访问的服务器上时,应用程序和会话变量会发生啥?

多个用户访问同一段代码

Nginx 实践案例:反向代理单台web;反向代理多组web并实现负载均衡

使用多用户 Web 界面的报告访问数据库