T
tuxedo
Gast
Hallo zusammen,
ich hab mal wieder ein eher spezielles Thema...
Wie meiner Signatur ja zu entnehmen ist, bastle ich an einer RMI-Alternative die keine Probleme mit Routern und Co. macht.
Die Socket-Implementierung funktioniert soweit. Mittlerweile hab ich auch eine Java NIO implementierung um mit seeeeehr vielen Clients umgehen zu können (theoretisch müsste RMI da vor SIMON in die Knie gehen...Stichwort "1 Thread pro Client").
Nun ja. Mein Problem ist leider immer noch, dass die Serialisierung und Deserialisierung, welche ja Grundlegendes Prinzip von RMI und SIMON ist, sehr langsam ist. Okay, ich muss die Aussage relativieren. SIMON ist langsamer als RMI. Und dank dem "Yourkit Java Profiler" (ein Dank geht an Vladimir von YourKit der mir eine kostenlose OpenSource Lizenz gegeben hat) wieß ich auch, dass die Serialisierung dran schuld ist.
Ein Beispiel:
RMI schafft es ein Transportobjekt, welches einen String plus ein byte[] mit 65kbyte Größe beinhaltet, 1000 zum Server und zurück zu kommunizieren, und das in etwa 1,3ms pro Durchlauf.
SIMON braucht da etwa 2,5-2,8ms und ist demnach rund doppelt so langsam (getestet auf einem Core2 Duo 2,13Ghz mit 2GB RAM und WinXP SP2, test lief via localhost)
Der Profiler sagt mir, dass in meinem Test, der 1byte - 65kbyte mit je 1000 Durchläufen testet, auf der Serverseite für die De-Serialisierung rund 1,2 Sekunden drauf gehen und dass das der Flaschenhals ist.
Jetzt steh ich etwas ratlos da. RMI benutzt wie SIMON auch ObjectInputStream und ObjectOutputStream. Damit werden Objekte in bytes verwandelt und umgekehrt. Primitive Datentypen wie Integer oder Float werden gesondert behandelt und in ihre byte-Repräsentation zerlegt (Integer besteht ja aus 4 Byte. Diese werden "einfach so" gesendet statt den Integer als Objekt zu serialisieren etc.). Diese Idee hab ich RMI schon abgekupfert und bei mir nachgebildet. Und dennoch hinkt SIMON RMI dermaßen hinterher.
Irgendwo in den Tiefen des RMI Sourcecodes muss noch etwas stecken das dem ganzen einen Performance-Schub gibt. Nur find ich's um's verrecken nicht. Den einzigsten Unterschied den ich jetzt noch entdeckt habe ist, dass RMI ThreadGroups verwendet. Aber ich hab gesagt bekommen dass man das lieber sein lassen sollte.
Nächster Knackpunkt war die umstellung auf NIO. Da gibts keine Streams mehr, weshalb das serialisierung via ObjectOutputStream darauf hinaus läuft, dass ich in einen ByteArrayOutputStream serialisiere, mir danach die Bytes aus dem BAOS hole und mit NIO verschicke.
Dazu hab ich im Netz gelesen dass es geschickter sei nicht den Umweg über byte[]s zu gehen, sondern einen eigene ByteOutputStream zu schaffen, welcher intern gleich ByteBuffer benutzt, was NIO zugute kommt da hier nur mit ByteBuffern gearbeitet wird und die lästige Konvertierung von byte[] nach ByteBuffer wegfällt.
Aber auch damit ist es nicht schneller geworden (aber auch nicht langsamer).
Ich weiß dass Externalisierung statt Serialisierung schneller ist, weil auch damit Object*Stream umgangen wird. Auch das hab ich versucht. Wird aber auch nicht schneller. Ich bin schier am verzweifeln.
Vielleicht kennt sich jemand etwas tiefer mit der Geschichte aus und kann mir den einen oder anderen Tipp geben.
Wie gesagt. Laut Profiler ist der HotSpot eindeutig das Serialisierung und Deserialisierung mittels der ObjectInputStrean ud ObjectOutputStream Methode.
Gruß
Alex
P.S. Okay, man könnte meinen dass bei einer Applikation die über das Internet kommuniziert es egal ist wenn ein Aufruf 1,3 oder 2,8ms braucht da die Latenz im Internet sowieso höher ist. Aber man muss auch berücksichtigen dass diese Messung indirekt wiedergibt wie schnell der Server antworten kann. Und das wiederum deutet darauf hin, dass der Server wohl mehr Antworten raushauen könnte wenn er nicht so viel mit Serialisierung und Deserialisieurng zu tun hätte. Für den einzelnen Client ist es also ertmal wurscht. Aber bei vielen Clients kann sich das negativ auf den Server und die Antwortzeiten auswirken.
ich hab mal wieder ein eher spezielles Thema...
Wie meiner Signatur ja zu entnehmen ist, bastle ich an einer RMI-Alternative die keine Probleme mit Routern und Co. macht.
Die Socket-Implementierung funktioniert soweit. Mittlerweile hab ich auch eine Java NIO implementierung um mit seeeeehr vielen Clients umgehen zu können (theoretisch müsste RMI da vor SIMON in die Knie gehen...Stichwort "1 Thread pro Client").
Nun ja. Mein Problem ist leider immer noch, dass die Serialisierung und Deserialisierung, welche ja Grundlegendes Prinzip von RMI und SIMON ist, sehr langsam ist. Okay, ich muss die Aussage relativieren. SIMON ist langsamer als RMI. Und dank dem "Yourkit Java Profiler" (ein Dank geht an Vladimir von YourKit der mir eine kostenlose OpenSource Lizenz gegeben hat) wieß ich auch, dass die Serialisierung dran schuld ist.
Ein Beispiel:
RMI schafft es ein Transportobjekt, welches einen String plus ein byte[] mit 65kbyte Größe beinhaltet, 1000 zum Server und zurück zu kommunizieren, und das in etwa 1,3ms pro Durchlauf.
SIMON braucht da etwa 2,5-2,8ms und ist demnach rund doppelt so langsam (getestet auf einem Core2 Duo 2,13Ghz mit 2GB RAM und WinXP SP2, test lief via localhost)
Der Profiler sagt mir, dass in meinem Test, der 1byte - 65kbyte mit je 1000 Durchläufen testet, auf der Serverseite für die De-Serialisierung rund 1,2 Sekunden drauf gehen und dass das der Flaschenhals ist.
Jetzt steh ich etwas ratlos da. RMI benutzt wie SIMON auch ObjectInputStream und ObjectOutputStream. Damit werden Objekte in bytes verwandelt und umgekehrt. Primitive Datentypen wie Integer oder Float werden gesondert behandelt und in ihre byte-Repräsentation zerlegt (Integer besteht ja aus 4 Byte. Diese werden "einfach so" gesendet statt den Integer als Objekt zu serialisieren etc.). Diese Idee hab ich RMI schon abgekupfert und bei mir nachgebildet. Und dennoch hinkt SIMON RMI dermaßen hinterher.
Irgendwo in den Tiefen des RMI Sourcecodes muss noch etwas stecken das dem ganzen einen Performance-Schub gibt. Nur find ich's um's verrecken nicht. Den einzigsten Unterschied den ich jetzt noch entdeckt habe ist, dass RMI ThreadGroups verwendet. Aber ich hab gesagt bekommen dass man das lieber sein lassen sollte.
Nächster Knackpunkt war die umstellung auf NIO. Da gibts keine Streams mehr, weshalb das serialisierung via ObjectOutputStream darauf hinaus läuft, dass ich in einen ByteArrayOutputStream serialisiere, mir danach die Bytes aus dem BAOS hole und mit NIO verschicke.
Dazu hab ich im Netz gelesen dass es geschickter sei nicht den Umweg über byte[]s zu gehen, sondern einen eigene ByteOutputStream zu schaffen, welcher intern gleich ByteBuffer benutzt, was NIO zugute kommt da hier nur mit ByteBuffern gearbeitet wird und die lästige Konvertierung von byte[] nach ByteBuffer wegfällt.
Aber auch damit ist es nicht schneller geworden (aber auch nicht langsamer).
Ich weiß dass Externalisierung statt Serialisierung schneller ist, weil auch damit Object*Stream umgangen wird. Auch das hab ich versucht. Wird aber auch nicht schneller. Ich bin schier am verzweifeln.
Vielleicht kennt sich jemand etwas tiefer mit der Geschichte aus und kann mir den einen oder anderen Tipp geben.
Wie gesagt. Laut Profiler ist der HotSpot eindeutig das Serialisierung und Deserialisierung mittels der ObjectInputStrean ud ObjectOutputStream Methode.
Gruß
Alex
P.S. Okay, man könnte meinen dass bei einer Applikation die über das Internet kommuniziert es egal ist wenn ein Aufruf 1,3 oder 2,8ms braucht da die Latenz im Internet sowieso höher ist. Aber man muss auch berücksichtigen dass diese Messung indirekt wiedergibt wie schnell der Server antworten kann. Und das wiederum deutet darauf hin, dass der Server wohl mehr Antworten raushauen könnte wenn er nicht so viel mit Serialisierung und Deserialisieurng zu tun hätte. Für den einzelnen Client ist es also ertmal wurscht. Aber bei vielen Clients kann sich das negativ auf den Server und die Antwortzeiten auswirken.