我的问题涉及JVM应用程序可以在多大程度上利用主机的NUMA布局。
我有一个Akka应用程序,其中actor通过将传入数据与已加载到不可变(Scala)对象中的“公共”数据相结合来并发处理请求。该应用程序使用许多双核VM在云中很好地扩展,但在单个64核计算机上表现不佳。我认为这是因为公共数据对象驻留在一个NUMA单元中,并且从其他单元同时访问的许多线程对于互连来说太多了。
如果我运行64个单独的JVM应用程序,每个应用程序包含1个actor,那么性能再次良好。一个更温和的方法可能是运行与NUMA单元一样多的JVM应用程序(在我的情况下为8),使主机操作系统有机会将线程和内存保持在一起?
但是有没有更聪明的方法在单个JVM中实现相同的效果?例如。如果我用一个案例类的几个实例替换我的公共数据对象,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之间成功交换“第一个心跳”之前存在很长的延迟(最多几分钟)。我怀疑还有其他问题,我还没有发现。我已经不得不增加ulimit -u,因为我达到了默认的最大进程数(1024)。
只是为了澄清,我并没有尝试获得大量的消息,只是试图让很多独立的actor同时访问一个不可变的对象。
答案 0 :(得分:2)
我认为如果您确定问题不在消息处理算法中那么您应该不仅考虑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。在我的笔记本电脑上,当池大小从4增加到64时,对于大多数执行器服务,此类案例的Akka演员的消息发送延迟增长了2-3倍(Scala的ForkJoinPool
,JDK的ForkJoinPool
,{{1} })。
您可以通过将ThreadPoolExecutor
系统变量设置为不同的值来运行mvnAll.sh
来检查是否存在任何差异。