7

我的问题涉及 JVM 应用程序可以在多大程度上利用主机的 NUMA 布局。

我有一个 Akka 应用程序,其中参与者通过将传入数据与已加载到不可变(Scala)对象中的“通用”数据组合来同时处理请求。该应用程序在云中可以很好地扩展,使用许多双核 VM,但在单个 64 核机器上表现不佳。我认为这是因为公共数据对象驻留在一个 NUMA 单元中,并且从其他单元同时访问的许多线程对于互连来说太多了。

如果我运行 64 个单独的 JVM 应用程序,每个应用程序包含 1 个参与者,那么性能又会很好。更温和的方法可能是运行与 NUMA 单元(在我的情况下为 8 个)一样多的 JVM 应用程序,让主机操作系统有机会将线程和内存保持在一起?

但是有没有更聪明的方法可以在单个 JVM 中实现相同的效果?例如,如果我用案例类的多个实例替换我的公共数据对象,JVM 是否有能力将它们放置在最佳 NUMA 单元上?

更新:

我正在使用 Oracle JDK 1.7.0_05 和 Akka 2.1.4

我现在尝试使用 UseNUMA 和 UseParallelGC JVM 选项。在使用一个或几个 JVM 时,两者似乎都不会对缓慢的性能产生任何显着影响。我也尝试过使用 PinnedDispatcher 和 thre-pool-executor,但没有任何效果。我不确定配置是否有效,因为启动日志中似乎没有什么不同。

当我为每个工作人员(约 50 个)使用单个 JVM 时,最大的改进仍然存在。但是,这个问题似乎是在 FailureDector 注册 Akka 集群 JVM 之间“第一次心跳”的成功交换之前有很长的延迟(最多几分钟)。我怀疑这里还有其他一些我尚未发现的问题。我已经不得不增加 ulimit -u 因为我达到了默认的最大进程数(1024)。

只是为了澄清一下,我不是试图获得大量消息,只是试图让许多单独的参与者同时访问一个不可变对象。

4

1 回答 1

2

我认为,如果您确定问题不在消息处理算法中,那么您不仅应该考虑 NUMA 选项,还应该考虑整个环境。配置,从 JVM 版本开始(最新的更好,Oracle JDK 也大多比 OpenJDK 性能更好),然后是 JVM 选项(包括 GC、内存、并发选项等),然后是 Scala 和 Akka 版本(最新的候选版本和里程碑可能会更好)还有 Akka 配置。

这里您可以借用所有重要的东西,以便在当代笔记本电脑上为 Akka 演员的总吞吐量每秒获得 50M 条消息

从来没有机会在 64 核服务器上运行这些基准测试 - 所以任何反馈都将不胜感激。

从我的调查结果来看,当池中的线程数量增加时,当前的实现会ForkJoinPool增加消息发送延迟。对于参与者之间的响应请求调用率很高的情况,例如在我的笔记本电脑上,当将池大小从 4 增加到 64 时,Akka 参与者的消息发送延迟对于大多数执行程序服务增长到 2-3 倍,这种情况非常明显(Scala 的ForkJoinPool,JDK 的ForkJoinPoolThreadPoolExecutor)。

mvnAll.sh您可以通过将benchmark.parallelism系统变量设置为不同值来检查是否有任何差异。

于 2013-05-29T10:48:21.760 回答