# rmi.transport.tcp.tcptransport Connectionhandler frisst 2/3 CPU



## dermoritz (8. Mrz 2011)

ich habe in eine externe Anwendung, die nichts anderes als ein RMI-Server mit spezieller Schnittstelle bereitstellt, meine eigene Anwendung (Implementierung der Schnittstelle*) eingebunden.
Der RMI-Server wird von einem Webserver bzw. einer dort installierten WebApp angesprochen. 

Das große Problem ist, dass der Server extrem CPU-lastig ist. Macht man Profiling mit JVisualVM fällt auf, dass 2/3 der CPU Zeit für "sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run()" draufgehen. An zweiter Position (find ich auch bemerkenswert) ist "sun.net.www.http.KeepAliveCache.run()" mit 16% CPU-Zeit. Summa Summarum gehen offensichtlich 80% für Netzwerkoverhead drauf?! 
Erst an 4. Stelle kommt die "eigentliche" CPU-Zeit "scale" der ImageIO.


Nun ist die Frage: hat irgendwer hier tiefere Ahnung von RMI und eventuell von entsprechender Betriebssystemkonfiguration (MS Server 2003) ? Ich gehe mal davon aus, dass so ein Overhead bei RMI nicht normal ist und das die entsprechenden Komponenten ihre CPU-Zeit mit warten verbringen?!


*Die Schittstelle bietet eine Methode "getImage()", die verwendete Implementierung holt sich das Image über einen WebService (Soap/Wsdl), skaliert es und liefert es als byte[] zurück.


----------



## tuxedo (9. Mrz 2011)

Ich denke das ist "normal". In dieser Klasse findet die Netzwerkkommunikation statt. Auch wenn du keine Remote-Methoden aufrufst, wird hier immer "gearbeitet". 

Die 80% sind ganz normal:

Wenn deine Anwendung nix tut, dann ist nur noch RMI "aktiv". Und dann geht eben die meiste CPU Zeit für's Nix-Tun drauf. Und das sieht dann so aus.

Die Sache mit dem Cache: Auch hier findet "RMI BlackBox Magie" statt. Der DGC (DistributedGarbageCollector) läuft auch im Hintergrund und checkt ob die Verbindung noch "lebt" etc...
Also auch wenn du nicht viel mit RMI kommunizierst: Auf Idle wird das Ding sogut wie nie gehen. Allerdings auch nicht von allein auf 100% cpu ..

Die Frage ist immer: 80% von wieviel?! 80% der CPU oder 80 der Zeit die die Anwendung auf der CPU bekommen hat? Letzteres muss nicht zwingend "schlecht"/"problematisch" sein.

Hast du denn ein Performance-Nadelöhr oder hast du einfach mal so den Profiler angemacht und die 80% "entdeckt"?


----------



## dermoritz (15. Mrz 2011)

das Problem wurde eigentlich erst durch ein Nadelöhr entdeckt. Im Moment können auf einer c2Duo (3ghz) Maschine nur ca. 30 Leute gleichzeitig den dienst nutzen (bei mehr wird es extrem Langsam und es kommt zu Timeouts).
Und wenn man sich dann überlegt, dass man den Dienst für einige hundert Leute anbieten muss, stellt man sich unweigerlich Fragen zur Skalierbarkeit. Insbesondere wenn nur ca. 20% der CPU-Zeit für die eigentlich Arbeit draufgeht.

Eine kleine Urache für den Overhead hab ich in der Software gefunden - dort wurde für jeden Aufruf eine Connection-Resource  (lokale Variable) benutzt. Nun ist das ein statisches Feld der Klasse und es sieht um einige besser aus: 
Wenn ich es nun ohne RMI direkt aufrufe (damit bleibt nur noch der eigentliche SOAP-Aufruf des Dienstes) sehe ich vom Kom-Overhead beim Profiling gar nix mehr (vorher 20% CPU-Zeit). 
Beim Umweg über RMI gibt es jedoch kaum Verbesserung (Anzahl maximaler Verbindungen ist gleich, aktuelles Profiling liegt grad nicht vor).

Die Frage wäre obe es Eurerseits ERfahrungen beim Implementieren von RMI gibt die helfen könnten das ganze effizienter zu machen. Oder ob man tatsächlich nur über die CPU skalieren muss.


----------



## tuxedo (15. Mrz 2011)

Da du ja schreibst dass auch im "User-Idle" die Server-CPU im stress ist, muss irgendwas bei dir schief sein.

Generell hat RMI keine Probleme damit viele Clients zu bedienen. Würde mal sagen einige wenige hundert sind kein Thema. 

Sollten es mehr werden und wird der Load den die Clients durch Methodenursache hervorrufen mehr, so bietet es sich an auf ein anderen IO-Konzept zu wechseln. 

RMI hat prinzipiell für jeden Client einen Thread. Wenn du nun 500 Clients hast die alle aktiv Kommunizieren, dann hast du ~500 Threads von und für RMI + die ganzen anderen Threads die du zur Verarbeitung der Client-Anfragen/Daten noch brauchst. Bei 5000 Clients dann 5000 Threads ... etc. 

Der Grund für dieses Verhalten ist die Nutzung von "blocking io". Hier benötigt man pro Client einen Thread.
SIMON geht hier den "non blocking io" weg. Hier kannst du angeben wieviele Threads sich um die Clients kümmern sollen. Dadurch skaliert SIMON besser wenn es um sehr viele Clients (sagen wir mal so ab 500 bis hin zu einigen Tausend) geht.

Alles in allem glaube ich aber dass RMI nicht für die Performanceprobleme verantwortlich ist die du beschreibst. Viel eher wird es die Implementierung sein die RMI ggf. "ungeschickt" verwendet...

Genaueres kann man erst mit dem Source-Code sagen. Aber vielleicht kannst du ein Minimalbeispiel basteln das das Problem aufzeigt?

- Alex


----------



## dermoritz (15. Mrz 2011)

Danke für die Infos,

das Problem ist wie gesagt, dass ich nicht an den Sourcecode des RMI-Servers komme. Ich benutze ihn nur und binde eine eigene jar-Datei ein.
Ich hatte gehofft, dass es allgemeine "RMI-Hinweise" gibt die ich den Entwicklern des RMI-Servers mitteilen könnte.


----------

