Ich habe eine Java-App, die über den TCP-Socket eine Verbindung zu einem in C / C ++ entwickelten "Server" herstellt.
App und Server laufen auf demselben Computer, einer Solaris-Box (wir erwägen jedoch eine eventuelle Migration auf Linux). Die Art der ausgetauschten Daten sind einfache Nachrichten (Login, Login ACK, dann Client fragt nach etwas, Server antwortet). Jede Nachricht ist ungefähr 300 Bytes lang.
Derzeit verwenden wir Sockets und alles ist in Ordnung. Ich suche jedoch nach einer schnelleren Möglichkeit, Daten mithilfe von IPC-Methoden auszutauschen (geringere Latenz).
Ich habe im Internet recherchiert und Hinweise auf folgende Technologien gefunden:
- geteilte Erinnerung
- Rohre
- Warteschlangen
- sowie was als DMA (Direct Memory Access) bezeichnet wird
Aber ich konnte keine richtige Analyse ihrer jeweiligen Leistungen finden und auch nicht, wie man sie sowohl in JAVA als auch in C / C ++ implementiert (damit sie miteinander sprechen können), außer vielleicht Pipes, die ich mir vorstellen könnte.
Kann jemand die Leistung und Machbarkeit jeder Methode in diesem Zusammenhang kommentieren? Gibt es einen Zeiger / Link zu nützlichen Implementierungsinformationen?
EDIT / UPDATE
Nach dem Kommentar und den Antworten, die ich hier erhalten habe, habe ich Informationen zu Unix Domain Sockets gefunden, die scheinbar nur über Pipes erstellt wurden und mir den gesamten TCP-Stack ersparen würden. Es ist plattformspezifisch, daher plane ich, es mit JNI oder entweder Juds oder Junixsocket zu testen .
Die nächsten möglichen Schritte wären die direkte Implementierung von Pipes und dann der gemeinsame Speicher, obwohl ich vor der zusätzlichen Komplexität gewarnt wurde ...
danke für Ihre Hilfe
Antworten:
Gerade getestete Latenz von Java auf meinem Corei5 2.8GHz, nur Einzelbyte senden / empfangen, 2 Java-Prozesse wurden gerade erzeugt, ohne bestimmte CPU-Kerne mit Task-Set zuzuweisen:
Geben Sie nun explizit Kernmasken an , z. B. Task-Set 1 Java Srv oder Task-Set 2 Java Cli :
so
Gleichzeitig dauert Thread.sleep (0) (was, wie Strace zeigt, dazu führt, dass ein einzelner Linux-Kernelaufruf sched_yield () ausgeführt wird) 0,3 Mikrosekunden - so genannte Pipes, die für einen einzelnen Kern geplant sind, haben immer noch viel Overhead
Einige Messungen des gemeinsam genutzten Speichers: 14. September 2009 - Solace Systems gab heute bekannt, dass seine Unified Messaging Platform-API mithilfe eines gemeinsam genutzten Speichertransports eine durchschnittliche Latenz von weniger als 700 Nanosekunden erreichen kann. http://solacesystems.com/news/fastest-ipc-messaging/
PS - am nächsten Tag versucht, gemeinsam genutzten Speicher in Form von Dateien mit Speicherzuordnung zu verwenden. Wenn das Warten auf viel zu tun akzeptabel ist, können wir die Latenz auf 0,3 Mikrosekunden reduzieren, um ein einzelnes Byte mit folgendem Code zu übergeben:
Anmerkungen: Thread.sleep (0) wird benötigt, damit 2 Prozesse die Änderungen des anderen sehen können (ich kenne noch keinen anderen Weg). Wenn zwei Prozesse mit dem Task-Set zum selben Kern gezwungen werden, beträgt die Latenz 1,5 Mikrosekunden - das ist eine Verzögerung beim Kontextwechsel
PPS - und 0,3 Mikrosekunden sind eine gute Zahl! Der folgende Code benötigt genau 0,1 Mikrosekunden, während nur eine primitive Zeichenfolgenverkettung ausgeführt wird:
PPPS - hoffe, dass dies nicht zu viel vom Thema abweicht, aber schließlich habe ich versucht, Thread.sleep (0) durch Inkrementieren einer statischen flüchtigen int-Variablen zu ersetzen (JVM leert dabei zufällig CPU-Caches) und erhalten - record! - 72-Nanosekunden-Latenz Java-zu-Java-Prozesskommunikation !
Wenn sie jedoch auf denselben CPU-Kern gezwungen werden, können sich flüchtige JVMs niemals gegenseitig steuern, wodurch eine Latenz von genau 10 Millisekunden erzeugt wird. Das Linux-Zeitquantum scheint 5 ms zu betragen. Dies sollte also nur verwendet werden, wenn ein Ersatzkern vorhanden ist. Andernfalls ist Schlaf (0) sicherer.
quelle
DMA ist eine Methode, mit der Hardwaregeräte auf physischen RAM zugreifen können, ohne die CPU zu unterbrechen. Ein gängiges Beispiel ist beispielsweise ein Festplattencontroller, der Bytes direkt von der Festplatte in den RAM kopieren kann. Als solches gilt es nicht für IPC.
Shared Memory und Pipes werden beide direkt von modernen Betriebssystemen unterstützt. Als solche sind sie ziemlich schnell. Warteschlangen sind normalerweise Abstraktionen, die z. B. über Sockets, Pipes und / oder gemeinsam genutztem Speicher implementiert werden. Dies mag wie ein langsamerer Mechanismus aussehen, aber die Alternative besteht darin, dass Sie eine solche Abstraktion erstellen.
quelle
Die Frage wurde vor einiger Zeit gestellt, aber Sie könnten an https://github.com/peter-lawrey/Java-Chronicle interessiert sein, das typische Latenzen von 200 ns und Durchsätze von 20 Millionen Nachrichten / Sekunde unterstützt. Es werden speicherabgebildete Dateien verwendet, die von Prozessen gemeinsam genutzt werden (es werden auch die Daten beibehalten, wodurch Daten am schnellsten beibehalten werden können).
quelle
Hier ist ein Projekt mit Leistungstests für verschiedene IPC-Transporte:
http://github.com/rigtorp/ipc-bench
quelle
Wenn Sie jemals in Betracht ziehen, nativen Zugriff zu verwenden (da sich sowohl Ihre Anwendung als auch der "Server" auf demselben Computer befinden), ziehen Sie JNA in Betracht , da Sie weniger Boilerplate-Code haben, mit dem Sie sich befassen müssen.
quelle
Eine späte Ankunft, wollte aber auf ein Open-Source-Projekt hinweisen, das sich der Messung der Ping-Latenz mit Java NIO widmet.
Weiter erforscht / erklärt in diesem Blogbeitrag . Die Ergebnisse sind (RTT in Nanos):
Dies entspricht der akzeptierten Antwort. Der System.nanotime () -Fehler (geschätzt durch nichts messen) wird bei etwa 40 Nanos gemessen, sodass für den IPC das tatsächliche Ergebnis möglicherweise niedriger ist. Genießen.
quelle
Ich weiß nicht viel über native Kommunikation zwischen Prozessen, aber ich würde vermuten, dass Sie mit nativem Code kommunizieren müssen, auf den Sie über JNI-Mechanismen zugreifen können. Von Java aus würden Sie also eine native Funktion aufrufen, die mit dem anderen Prozess kommuniziert.
quelle
In meiner früheren Firma haben wir mit diesem Projekt gearbeitet, http://remotetea.sourceforge.net/ , das sehr einfach zu verstehen und zu integrieren ist.
quelle
Haben Sie darüber nachgedacht, die Steckdosen offen zu halten, damit die Verbindungen wiederverwendet werden können?
quelle
Oracle-Fehlerbericht zur JNI-Leistung: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4096069
JNI ist eine langsame Schnittstelle und daher sind Java-TCP-Sockets die schnellste Methode zur Benachrichtigung zwischen Anwendungen. Dies bedeutet jedoch nicht, dass Sie die Nutzdaten über einen Socket senden müssen. Verwenden Sie LDMA, um die Nutzdaten zu übertragen. Wie bereits in früheren Fragen erwähnt , ist die Java-Unterstützung für die Speicherzuordnung nicht ideal, und Sie sollten daher eine JNI-Bibliothek implementieren, um mmap auszuführen.
quelle