2013-05-28 11 views
7

Meine Frage betrifft das Ausmaß, in dem eine JVM-Anwendung das NUMA-Layout eines Hosts ausnutzen kann.NUMA Bekanntheit von JVM

Ich habe eine Akka-Anwendung, in der Akteure gleichzeitig Anfragen verarbeiten, indem sie eingehende Daten mit "gemeinsamen" Daten kombinieren, die bereits in ein unveränderliches (Scala) -Objekt geladen wurden. Die Anwendung skaliert gut in der Cloud, indem sie viele Dual-Core-VMs verwendet, aber auf einer einzelnen 64-Core-Maschine schlecht abschneidet. Ich nehme an, dies liegt daran, dass das gemeinsame Datenobjekt in einer NUMA-Zelle liegt und viele Threads, auf die gleichzeitig von anderen Zellen zugegriffen wird, zu viel für die Verbindungen sind.

Wenn ich 64 separate JVM-Anwendungen mit jeweils 1 Akteur ausführen, dann ist die Leistung wieder gut. Ein moderaterer Ansatz könnte darin bestehen, so viele JVM-Anwendungen auszuführen, wie NUMA-Zellen vorhanden sind (in meinem Fall 8), was dem Host-Betriebssystem die Möglichkeit gibt, die Threads und den Speicher zusammenzuhalten?

Aber gibt es eine klügere Möglichkeit, denselben Effekt in einer einzelnen JVM zu erzielen? Z.B. Wenn ich mein gemeinsames Datenobjekt durch mehrere Instanzen einer Fallklasse ersetzen würde, hätte die JVM dann die Möglichkeit, sie in der optimalen NUMA-Zelle zu platzieren?

Update:

Ich bin mit Oracle JDK 1.7.0_05 und Akka 2.1.4

Ich habe jetzt versucht, mit der UseNUMA und UseParallelGC JVM-Optionen. Bei einer oder wenigen JVMs schien keiner der beiden Faktoren einen signifikanten Einfluss auf die langsame Performance zu haben. Ich habe auch versucht, einen PinnedDispatcher und den Three-Pool-Executor ohne Wirkung zu verwenden. Ich bin mir nicht sicher, ob die Konfiguration einen Effekt hat, da in den Startprotokollen nichts anderes zu finden ist.

Die größte Verbesserung bleibt, wenn ich eine einzelne JVM pro Arbeiter (~ 50) verwende. Das Problem dabei scheint jedoch zu sein, dass es eine lange Verzögerung (bis zu einigen Minuten) gibt, bevor der Fehlerdetektor den erfolgreichen Austausch des "ersten Herzschlags" zwischen Akka-Cluster-JVMs registriert. Ich vermute, dass es hier ein anderes Problem gibt, das ich noch nicht aufgedeckt habe. Ich musste bereits die ulimit -u erhöhen, da ich die standardmäßige maximale Anzahl von Prozessen (1024) erreichte.

Nur um zu verdeutlichen, versuche ich nicht, eine große Anzahl von Nachrichten zu erreichen, sondern versuche nur, viele separate Akteure gleichzeitig auf ein unveränderliches Objekt zugreifen zu lassen.

+2

Verwenden Sie die Option -XX: + UseNUMA jvm? – cmbaxter

+0

Welche GC-Einstellungen verwenden Sie? Und welche Executor-Konfiguration? –

+0

Sie müssen wahrscheinlich akka sagen, bessere Threading-Muster zu verwenden, sehen Sie hier für einige Mailbox-Konfigurationsoptionen: http://doc.akka.io/docs/akka/snapshot/scala/dispatchers.html – Noah

Antwort

2

Ich denke, wenn Sie sicher, dass Probleme nicht in der Nachrichtenverarbeitung Algorithmen dann sollten Sie nicht nur NUMA-Option, sondern ganze env berücksichtigen. Konfiguration, beginnend mit der JVM-Version (das letzte ist besser, Oracle JDK ist auch meist besser als OpenJDK), dann JVM-Optionen (einschließlich GC, Speicher, Nebenläufigkeitsoptionen usw.), dann Scala und Akka-Versionen (neueste Release-Kandidaten und Meilensteine ​​können viel besser sein) und auch Akka-Konfiguration.

Von here können Sie alle Dinge ausleihen, die wichtig sind, erhalten 50M messages per second of total throughput for Akka actors on contemporary laptops.

Niemals die Möglichkeit gehabt, diese Benchmarks auf einem 64-Core-Server laufen zu lassen - daher wird jedes Feedback sehr geschätzt.

Aus meinen Erkenntnissen, die helfen können, erhöht aktuelle Implementierungen von ForkJoinPool Nachricht senden Latenz, wenn die Anzahl der Threads im Pool erhöht. Es ist stark bemerkbar für Fälle, in denen die Rate des Antwortanforderungsaufrufs zwischen den Akteuren hoch ist, z.B. G. auf meinem Laptop, wenn Pool-Größe von 4 bis 64 Nachricht zu erhöhen, senden Latenz der Akka-Akteure für solche Fälle bis zu 2-3x für die meisten Executor-Dienste (Scala ForkJoinPool, JDK ForkJoinPool, ThreadPoolExecutor).

Sie können prüfen, ob Unterschiede bestehen, indem Sie mvnAll.sh mit der Systemvariablen benchmark.parallelism auf verschiedene Werte setzen.

+0

Hier ist ein Blogbeitrag, der das Skalierbarkeitsprofil von akka auf unserem 48-Core-Testserver mit FJP beschreibt: http://letitcrash.com/post/20397701710/50-million-messages-per-second-on-a-single-machine –