如何在执行许多异步后台任务时保持Web服务器的响应

时间:2017-08-28 15:38:10

标签: spring multithreading tomcat asynchronous aop

我正在开发一个Web应用程序,该应用程序为其用户提供可选地执行长时间运行的进程“ 在后台 ”。一个例子是一些长期运行的报告生成,或同时删除数千个对象。

我使用ThreadFactory使用定义为FixedThreadPool的ExecutorService实现了这一点。 ThreadFactory的构建如下:

ThreadFactoryBuilder()
            .setNameFormat(clientId + "-BackgroundTask-%d")
            .setDaemon(true)
            .setPriority(Thread.MIN_PRIORITY)
            .build()

我执行这样的任务:

Future<TaskStatus> future = clientExecutors.get(clientId).submit(
            backgroundTask::execute);
    taskFutures.put(backgroundTask.getTaskId(), future);

如何执行我的网络服务器始终优先处理新的传入请求(尽快)执行后台任务?

换句话说:用户不得不在浏览网站时等待很长时间,因为有很多后台任务正在执行。从上面可以看出,我尝试通过设置.setPriority(Thread.MIN_PRIORITY)来做到这一点。然而,这似乎还不够。

此外,就目前而言,我为FixedThreadPool size(10)设置了一些任意值,并将其全局用于应用程序(及其所有客户)的整个后台处理。

相反,我想为每个客户定义一个线程池,以确保每个客户具有在后台运行一定数量任务的相同权限。比如说,每个客户都有一个5号的FixedThreadPool,在服务器上我会有最大值。 50个不同的客户。这将同时增加250个正在运行的后台任务。

这里最重要的要求是:无关紧要,这些后台任务需要执行多长时间(例如2分钟或20分钟)。重要的是,每个客户都有能力发送5个后台执行的任务,并且每个任务都在同等上工作。

我已经测试过运行30个cpu密集型后台任务,结果发现这些任务正在运行且cpu接近100%时,新的传入请求需要很长时间才能处理。

很明显,我做错了。

更新12.09.2017 我已经阅读过关于微服务的内容,虽然听起来很棒,但我认为从单片应用程序中分离必要的部分是一个巨大的挑战。主要是因为在给定足够大的数据选择的情况下,几乎每个操作都可能变成长时间运行的过程 此外,我不会遇到与我的微服务相同的问题,即运行微服务的服务器会遭受相同的性能下降。那么唯一的好处就是,网络应用程序的其余部分将不再受其影响。

我已经阅读了一些关于将Thread.sleep(1)或Thread.sleep引入CPU繁重操作的帖子,以减少这些操作中使用的CPU数量。我还读到了有人将这个作为一个方面介绍,以便他甚至可以改变动态等待的时间,以便控制将使用多少cpu。

然而,我的直觉告诉我,这也不对。您如何考虑引入Thread.sleep来降低任务使用的CPU数量?这是常见做法吗?如果没有,那么什么是正确的方法?

1 个答案:

答案 0 :(得分:1)

我会高度考虑更改您的系统体系结构,以将这些长时间运行的请求卸载到单独的实例,而不是使用通用请求服务应用程序在进程中运行它们。一般来说,我认为在同一个应用程序实例中处理批处理/在线(或长/短运行)处理是一种反模式。

理想情况下,您构建一个独立的微服务来处理这些请求,但您也可以简单地部署现有应用程序的X实例,并配置负载均衡器以将请求路由到长时间运行的调用路径(例如{{1} })仅适用于运行这些长时间运行的进程的实例。