我在tomcat服务器上运行RESTful样式的RPC(远程过程调用)API,该服务器在K个线程上处理具有M个任务的N个用户的数据。大多数情况下,一个用户有大约20到500个任务(但M可能在1到5000之间)。一项任务需要大约10到20秒才能完成,但可以在1秒到20分钟之间。目前,大多数系统有一个用户,有时最多三个,但在不久的将来它会同时增加到大约10个用户。我们的服务器有10个内核,因此我想使用10个线程。目前,每个用户都有5个线程进行处理,效果很好。但是a)大多数时候机器仅使用50%(导致针在“30分钟”范围内等待),有时服务器负载高达150%。
解决方案的要求:
想到的解决方案:
只使用10个线程的FixedThreadPoolExecutor,违反条件3
使用PriorityBlockingQueue并在我的任务中实现compareTo方法 - >不能使用threadpoolExecutors提交方法(因此我不知道提交的任务何时结束)
实现像阻塞队列一样的“循环”,其中K个线程(在我们的例子中为10)以循环方式从N个内部队列中获取新任务 - >为了能够将任务放入正确的队列,我需要一个“提交”方法,该方法需要多个参数(我也需要实现一个ThreadPoolExecutor)
我试图用循环法来说明我的意思,比如阻止队列(如果没有帮助,可以随意编辑它):
-- -- -- -- -- -- queue task load, -- -- -- -- -- -- -- one task denoted by -- -- -- -- -- -- -- -- -- | Q1 | Q2 | Q3 | Q4 | Q5 | Q6 | Q7 | QN | | * ^ | | last| |next | | ------------- \ / \ | | | | | | T1 | T2 | T3 | T4 | TK |
是否有一个优雅的解决方案,主要使用Java标准API(或任何其他广泛的Java API)来实现这种处理行为(可能是我提出的解决方案之一或任何其他解决方案)?或者您对如何解决这个问题有任何其他提示?
答案 0 :(得分:0)
如果您同意最小化整体任务延迟是对要求2和3的良好替代,并且您有足够好的任务运行时估计,那么我可能会得到答案。
您可以将任务提交时间存储在每个任务中,以便以后可以随时计算其估计的延迟。 然后,您可以构建PriorityBlockingQueue,在插入新任务时,始终将其插入到提供一定公平性的队列位置,并尝试最小化总体延迟。首先,这将使长期运行的任务处于不利地位。我自己没有尝试过,但我会根据您的估计运行时间分配任务优先级,并使用estimatedRuntime-waitingTime作为优先级(首先采用最低级别的prreeity工作)。在等待足够的负面优先权之后,这将给重型任务带来机会。在那之前,轻量级任务将有更好的机会成为第一,即使它们刚刚被提交。但是,这种安排只会如您的估计所允许的那样公平。
至于循环要求:如果这非常重要,您也可以在队列中处理此问题。基本上,当您使用线程池时,您可以根据在队列中插入新作业的位置来实现您的调度策略。如果您可以估算作业延迟,则可以通过插入正确的位置来平衡用户。
答案 1 :(得分:0)
满足您的要求:
1)最大化线程使用:任何ThreadPoolExecutor都会处理这个问题 2)所有用户都被视为相同:基本上需要循环设置 3)避免新用户按FIFO顺序等待:与#2相同。
你也提到了提交和获得结果的能力。
您可以考虑使用包装器对象的独立PriorityBlockingQueue<Job>
,例如:
class Job implements Comparable<Job> {
private int priority;
private YourCallable task;
public Job(int priority, YourCallable task) {
this.priority = priority;
this.task = task;
}
@Override
public int compareTo(Job job) {
// use whatever order you prefer, based on the priority int
}
}
您的制作人向PriorityBlockingQueue提供作业,并指定优先级(基于您的循环规则或其他),以及实现Callable的任务。然后,您的消费者会为作业执行queue.poll。
掌握完毕后,您可以获取该Job对象中包含的任务,并将其发送给您选择的ThreadPoolExecutor进行处理。
答案 2 :(得分:0)
我一直致力于类似于循环设置的解决方案。它变得非常复杂,但我想我想出了一个不错的实现。它可能不是一个非常优雅的解决方案,但有单元测试显示一些功能。不幸的是,TaskQ尚未处于“1.0”阶段。
它涵盖了您的第1至3点:
目前还没有手册/文档,希望您能抽出时间进行调查。显示某些用法的单元测试是here,扩展/使用的主要类是RunnableTaskQWithQos。