Java的“分层队列”实现,用于快速生产者和慢速消费者。

5

我有一个生产者-消费者场景,其中生产者的生产速度比消费者能够消费的速度快得多。通常的解决方案是使生产者阻塞,因为生产者/消费者场景的操作速度与最慢的组件一样快。限流或阻止生产者不是好的解决方案,因为我们的应用程序提供足够的时间让消费者稍后赶上。

以下是我们应用程序中完整“阶段”的示意图,与更常见的情况进行对比:

      Our Application                 Common Scenario
 2N +--------+--------+
    |PPPPPPPP|oooooooo|                                         P = Producer
    |PPPPPPPP|oooooooo|                                         C = Consumer
  N +--------+--------+      N +--------+--------+--------+     o = Other Work
    |CPCPCPCP|CCCCCCCC|        |CPCPCPCP|CPCPCPCP|oooooooo|     N = number of tasks
    |CPCPCPCP|CCCCCCCC|        |CPCPCPCP|CPCPCPCP|oooooooo|
    -------------------        ----------------------------
    0       T/2       T        0       T/2       T      3T/2

这里的思路是通过不阻碍生产者来最大化吞吐量。
我们的任务操作的数据很容易进行序列化,所以我计划实现一个文件系统解决方案,用于溢出所有无法立即满足的任务。
我正在使用Java的ThreadPoolExecutor和一个具有最大容量的BlockingQueue,以确保我们不会耗尽内存。问题在于实现这样一个“分层”队列,其中可以在内存中排队的任务会立即完成,否则数据将在磁盘上排队。
我想出了两个可能的解决方案:
1.从头开始实现一个BlockingQueue,使用LinkedBlockingQueue或ArrayBlockingQueue实现作为参考。这可能就像复制标准库中的实现并添加文件系统读/写一样简单。
2.继续使用标准的BlockingQueue实现,实现一个单独的FilesystemQueue用于存储我的数据,并使用一个或多个线程来出列文件、创建Runnable并使用ThreadPoolExecutor排队它们。
这些方法是否合理?还有更好的方法吗?
3个回答

4
在采用更复杂的解决方案之前,您是否真的有信心使用有界的BlockingQueue会成为你的致命伤?也许增加堆大小并预先分配足够大的容量仍然可以满足您的需求。这将使您避免复杂性和性能不确定性,代价是GC暂停,但这已经在您的舒适区内了。
如果工作负载如此不均衡以至于需要存储无法放入内存(与经过验证的MPMC阻塞队列相比)的消息数量,那么听起来您需要一个更简单,更小的版本ActiveMQ或其Apollo分支。根据您的应用程序,您可能会发现ActiveMQ的其他特性非常有用,如果是这样,您可以直接使用它。如果没有,您最好搜索JMS领域,正如 bowmore 所建议的那样。

2
这种情况最好使用JMS队列,而不是文件系统。将消息发布到持久化的JMS队列中,而不是使用阻塞式队列。你仍然可以尝试分层方法,将JMS队列与BlockingQueue并行使用,在BlockingQueue满时将消息发布到JMS队列中,但我相信纯JMS方法自身也可以正常工作。

2
第一种选择是增加可用的堆空间大小,正如Dimitar Dimitrov建议的那样,使用内存标志“-Xmx”,例如“java -Xmx2048m”。
从Oracle文档中可以看到:请注意,JVM使用的内存不仅仅是堆。例如,Java方法、线程堆栈和本机句柄都分配在与堆不同的内存中,以及JVM内部数据结构。
这里还有一个关于Java堆内存如何分类的图表。

enter image description here


第二个选项是使用实现所需功能的库。为此,您可以使用ashes-queue 从项目概述中看到:这是Java中的简单FIFO实现,具有持久性支持。也就是说,如果队列已满,则溢出的消息将被持久化,当有可用的插槽时,它们将被放回内存中。
第三个选择是创建您自己的实现。为此,您可以预览this thread,该主题将指导您完成此操作。 您的建议包括在这最后一个选项中。两者都是合理的。从实现的角度来看,您应该选择第一种选择,因为它将保证更容易的实现和清晰的设计。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接