2014-02-12 27 views
0

我需要构建一个作业处理模块,其中作业的传入速率为数百万次。我有一个多处理器机器来运行这些作业。在我当前使用的解决方案Java中,我使用Java的ThreadPoolExecutor框架创建作业队列LinkedListBlockingQueue,并且线程数等于系统上可用的处理器。由于作业队列保持增长,此设计无法支持传入速率,即使CPU利用率未达到最大值,它也会在几秒内报告溢出。 CPU利用率保持在30-40%的范围内。Java:如何构建可扩展的作业处理机制

这意味着大部分时间都会在其他CPU空闲的线程争用中消失。有没有更好的处理作业的方式,以便更好地利用CPU,使作业队列不会溢出?

+0

由于您的电脑利用率太低,这表明有更多的处理带宽..也许增加线程数量将有助于你的情况。尽管分析你的工作可能会让人想到需要多少线程。线程彼此等待的时间越多,您可以创建的线程利用未使用的处理能力越多。但是,如果你在几秒钟内崩溃,即使这不会帮助。也许你需要更多的计算机来分配工作? –

+0

不,线程正在队列中等待按顺序执行作业,该作业持有一个锁,因此当一个线程调用queue.take()时,其他线程将等待。我认为引入更多线程只会使情况更加恶化,因为每个线程都必须等待。可能更多的线程可以帮助,如果工作处理时间更多,每个工作正在做一些I/O,对吧? –

+0

对于如此沉重的负载,即使您设计的高效执行器,传入速率可能会变得过高,并且所有可用内存将被作业队列占用。为了避免它,使用固定或有限容量的ArrayBlockingQueue。与LinkedBlockingQueue相比,它还节省了链接的内存。 –

回答

2

我建议你先看看Disruptor。这在内存环形缓冲区中提供了高性能。如果消费者无法跟上,那么你可以减缓生产者的速度,这样做效果最好。

如果你需要我建议使用Chronicle(这是我写的),这有生产者不生产商放慢了优势(和队列是完全堆外)

这两个一个持久或无界队列旨在处理每秒数百万条消息。

+0

“制片人没有被制片人放慢”?我觉得有一个消费者在那里失踪;-) –

1

嗨你可以使用像RabbitMQ这样的排队系统来保存消息进行处理。如果将它与Spring AMQP结合使用,您可以轻松实现(一行配置)多线程,并且邮件将存储在磁盘上,直到它们准备好被应用程序处理。

+0

您可以添加有关此解决方案适合的吞吐量的评论吗? –

+1

我们已经使用排队处理任何事情,每天有数千次交易,每天有一百万次以上的交易。 AMQP/JMS显然不是没有缺点。我觉得它提供了很多开箱即用的功能,并简化了代码,因为管理作业队列已从您的应用程序中删除。我不是说这是正确的方式,但也许是OP想要探索的选项。 –

1

您的分析可能是错误的。如果CPU正在忙于切换作业,则CPU利用率将为100% - CPU为进程执行的任何操作都会计数。

我的猜测是,你有I/O,你可以运行更多的工作。尝试运行比CPU核多4至8倍的线程。

如果结果太慢,请使用类似Akka which can process 10 million messages in 23 seconds without any special tuning的框架。如果这还不够,那么看看Disruptor

+0

好吧,是的,这是有道理的。我的意思是我不记得检查每个CPU利用率,我的意思是整体多处理器CPU使用率徘徊在30-40%左右。让我回去检查是否有任何一个CPU忙于做所有的切换,并最终得到最大化。 –

+0

我还会在增加线程数后检查性能。 –

+0

增加线程数实际上增加了CPU使用率。感谢大家的回应.. :) –

0

不可思议的图书馆很诱人,但往往误导你错误的方向,并使你的解决方案日复一日更复杂......干扰人LMAX也这样说:)我认为你应该退后一步,了解根作业队列深度的原因。在你的情况下,看起来同样类型的消费者,所以我不认为干扰者会帮助。 你提到过关于线程争用。 我建议先尝试看看是否可以减少争用。不知道你的所有工作是否相关,但如果不是,可以使用一些排队技术,并减少不相关的工作争用。那么你需要知道你的消费者为什么很慢。您可以通过在使用者中使用ReadWrite锁或NonBlocking集合来改进锁定策略。