我的问题与JVM应用程序能够利用主机的NUMA布局的程度有关。
我有一个Akka应用程序,其中actor通过将传入数据与已加载到不可变(Scala)对象中的“公共”数据组合来并发处理请求。该应用程序在云中使用许多双核VM时具有良好的扩展性,但在单个64核机器上表现不佳。我认为这是因为公共数据对象驻留在一个NUMA单元中,并且许多线程同时从其他单元访问过于频繁,导致了互连的负担过重。
如果我运行64个包含1个actor的单独的JVM应用程序,则性能会恢复正常。一个更温和的方法可能是运行与NUMA单元数相同的JVM应用程序(在我的情况下为8个),使主机操作系统有机会将线程和内存保持在一起?
但是,在单个JVM内实现相同效果是否有更聪明的方法?例如,如果我用几个case类的实例替换我的公共数据对象,JVM是否有能力将它们放置在最佳的NUMA单元上?
更新:
我正在使用Oracle JDK 1.7.0_05和Akka 2.1.4
我现在尝试了UseNUMA和UseParallelGC JVM选项。当使用一个或少量的JVM时,两者似乎都没有任何显着的影响。我还尝试使用PinnedDispatcher和three-pool-executor,但没有效果。虽然启动日志中似乎没有任何不同,但我不确定配置是否产生了影响。
最大的改进仍然是当我为每个工作进程使用单个JVM(约50个)时。但是,这样做的问题似乎是在Akka集群JVM之间成功交换“第一个心跳”的FailureDector注册之前存在长时间的延迟(多达几分钟)。我怀疑这里还有其他问题,我尚未发现。我已经不得不增加ulimit -u,因为我达到了默认最大进程数(1024)。
只是为了澄清,我并不试图实现大量消息,只是试图让许多单独的actor同时访问一个不可变对象。
我有一个Akka应用程序,其中actor通过将传入数据与已加载到不可变(Scala)对象中的“公共”数据组合来并发处理请求。该应用程序在云中使用许多双核VM时具有良好的扩展性,但在单个64核机器上表现不佳。我认为这是因为公共数据对象驻留在一个NUMA单元中,并且许多线程同时从其他单元访问过于频繁,导致了互连的负担过重。
如果我运行64个包含1个actor的单独的JVM应用程序,则性能会恢复正常。一个更温和的方法可能是运行与NUMA单元数相同的JVM应用程序(在我的情况下为8个),使主机操作系统有机会将线程和内存保持在一起?
但是,在单个JVM内实现相同效果是否有更聪明的方法?例如,如果我用几个case类的实例替换我的公共数据对象,JVM是否有能力将它们放置在最佳的NUMA单元上?
更新:
我正在使用Oracle JDK 1.7.0_05和Akka 2.1.4
我现在尝试了UseNUMA和UseParallelGC JVM选项。当使用一个或少量的JVM时,两者似乎都没有任何显着的影响。我还尝试使用PinnedDispatcher和three-pool-executor,但没有效果。虽然启动日志中似乎没有任何不同,但我不确定配置是否产生了影响。
最大的改进仍然是当我为每个工作进程使用单个JVM(约50个)时。但是,这样做的问题似乎是在Akka集群JVM之间成功交换“第一个心跳”的FailureDector注册之前存在长时间的延迟(多达几分钟)。我怀疑这里还有其他问题,我尚未发现。我已经不得不增加ulimit -u,因为我达到了默认最大进程数(1024)。
只是为了澄清,我并不试图实现大量消息,只是试图让许多单独的actor同时访问一个不可变对象。