我的问题与JVM应用程序可以利用主机的NUMA布局的程度有关。

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

如果我运行64个单独的JVM应用程序,每个应用程序包含1个actor,那么性能将再次良好。较为温和的方法可能是运行与NUMA单元一样多的JVM应用程序(在我的情况下为8),是否为主机OS提供了将线程和内存保持在一起的机会?

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

更新:

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

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

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

为了澄清起见,我并不是在尝试获取大量消息,而是在试图让许多不同的参与者同时访问一个不可变的对象。

最佳答案

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

您可以从here借用所有重要的东西来获得50M messages per second of total throughput for Akka actors on contemporary laptops

从未有过在64核服务器上运行这些基准测试的机会-因此,我们将不胜感激任何反馈。

根据我的发现,这可能会有所帮助,当池中的线程数增加时,ForkJoinPool的当前实现会增加消息发送延迟。在参与者之间的响应请求调用率很高的情况下,例如,这种情况非常明显。 G。在我的笔记本电脑上,当这种情况下,Akka actor的发送池延迟从4个增加到64个消息时,大多数执行器服务(Scala的ForkJoinPool,JDK的ForkJoinPoolThreadPoolExecutor)的发送延迟增加到2-3倍。

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

09-05 08:42
查看更多