(WS11-06) JBoss AS7 Performance-Instrumentierung

Aus Verteilte Systeme - Wiki
Version vom 22. Februar 2012, 09:44 Uhr von Jschaefe (Diskussion | Beiträge) (Schützte „(WS11-06) JBoss AS7 Performance-Instrumentierung“: LV abgeschlossen ([edit=sysop] (unbeschränkt) [move=sysop] (unbeschränkt)))
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Einleitung

Apache Axis2

Apache Axis2 (Apache eXtensible Interaction System) ist ein Open Source basierendes Framework zur Implementierung von Web-Service-Anwendungen und ist eines der am meisten eingesetzten Web-Service-Frameworks für Java. Apache Axis ist eine SOAP-Engine und wie der Name schon verrät, ist Apache Axis ein Projekt der Apache Software Foundation. Axis2 ist der Nachfolger von Axis 1.x und unterscheidet sich von diesem Vorgänger durch ein performanteres Framework.

ARM-Grundlagen

ARM ist ein Standard der OpenGroup zur Messung von Antwortzeiten in einfachen und verteilten Anwendungen. Dieser Standard definiert eine Schnittstelle in Form einer API, die von Software-Entwickler zur Instrumentierung ihrer Anwendung verwendet werden können. Diese API ist für die Programmiersprachen Java und C/C++ verfügbar. Die ARM-API besteht jedoch nur aus Schnittstellen, die ARM-Funktionalitäten werden daher in diesem Projekt durch das Instrumentierung- und Management-Tool tang-IT der tang-IT Consulting GmbH bereitgestellt.

ARM-Transaction

Im ARM-Standard bezeichnet eine Transaktion (unit of work) die Messung der Antwortzeit eines definierbaren Codeabschnitts.

Geschachtelte Transaktionen

Mit ARM ist es möglich Transaktionen zu schachteln, es entsteht dabei eine Eltern/Kind-Beziehung. Dabei ist es nicht notwendig, dass die Eltern- und Kind-Transaktionen vom selben ARM-Agenten vermessen werden. Die Abbildung der Beziehung zwischen Transaktionen wird durch einen sog. Correlator ermöglicht.

Projektziel

Ziel dieses Projektes ist eine Performance Instrumentierung von Apache Axis2 mit Hilfe der ARM-Bibliothek (Application Measurement Response). Durch einen einfachen Webservice, soll gezeigt werden, wie eine Performancemessung mit der ARM-Bibliothek erfolgt. Die Performance Instrumentierung erfolgt hier durch ein White-Box-Verfahren, denn Kenntnisse über das System erforderlich sind, um Messpunkte in dieses einzubringen.

Problemanalyse

Durch die Service Level Agreements (SLAs) hat die Bedeutung der Performance einer Applikation im Bereich der Software-Entwicklung zugenommen. In dieser SLA, die einen Vertrag zwischen Auftraggeber und Dienstanbieter bezeichnet, werden Leistungseigenschaften wie Reaktionszeit und Schnelligkeit der zu entwickelten Applikationen dem Kunden zugesichert.

Zur Messung der Antwortzeit einer Applikation wird meistens die Uhrzeit des zugrunde liegenden Betriebssystems ausgelesen. Wenn es aber um die Messung von Programmen geht, die nur einige Bruchteile von Millisekunden dauern, braucht man spezielle Funktionen, wie die Funktion System.nanoTime() in Java oder die Funktionen gettimeofday() und clock() in C/C++. Management-Tools wie das ARM API liefern dabei präzisere Messungen und machen es möglich, die gemessenen Zeiten auszuwerten. Mit ARM ist es sogar möglich, die Antwortzeiten einer Applikation der Client- und Service-Seite in einem "Unit of work" zusammenzufassen. Dies erfolgt durch die Verwendung des sogenannten Correlator, der beim Aufruf des Services als Parameter übergeben wird.


Konzept

Da eine Performancemessung immer auf einer Applikation stattfindet, wird für dieses Projekt, wie schon in der Einleitung erwähnt, ein Axis2-Webservice entwickelt. Dieser Werbservice bietet die einfachsten Operationen eines Taschenrechners, nämlich die Addition, Multiplikation und Division. Jede dieser Operationen erwartet drei Parameter: die zwei Zahlen die miteinander verrechnet werden sollen und einen Correlator als Byte-Array.


Verfügbare Operationen

addition (double zahl_a, double zahl_b, byte[] correlator)

multiplikation (double zahl_a, double zahl_b, byte[] correlator)

division (double zahl_a, double zahl_b, byte[] correlator)

Zur Konsumierung des Services wird auch einen Client entwickelt, der die zur Verfügung stehenden Operationen aufruft.

Die Instrumentierung wird sowohl auf dem Client, als auch auf dem Server durchgeführt. Dadurch kann im Fall einer zu langer Antwortzeit genau festgestellt werden, ob der Service, der Client oder eher die Netzwerkverbindung für die langsame Reaktionszeit verantwortlich ist.

Um einen Gefühl der Ausführungszeit von ARM selbst zu bekommen, wird eine primitive Instrumentierung(ohne ARM) durchgeführt. Dafür wird den Service aufgerufen, wobei vor und nach jedem zu messenden Codeabschnitt die Zeit aufgenommen wird. Danach kann der Service nochmal aufgerufen werden, aber diesmal mit einer ARM-Instrumentierung. Es wird bei diesem zweiten Aufruf vor jedem Transaktion-Start und nach jedem Transaktion-Stop ebenfalls die Zeit aufgenommen. Am Ende werden die Zeitdifferenzen beider Aufrufe miteinander verglichen. Die Differenz ergibt dann das gewünschte ARM-Overhead.

Simulation paralleler Service-Aufrufe

ARM kann benutzt werden, um Performance-Engpässe ausfindig zu machen. Um ein solches Szenario zu simulieren wird mit einer Batch-Datei der Instrumentierte Webservice mehrmals und parallel aufgerufen. Um den Client von der Batch-Datei aufrufen zu können, muss dieser als ausführbare Jar-Datei exportiert und im selben Ordner mit dem File build.xml des Eclipse-Projektes gespeichert werden

Realisierung

Instrumentierung

Instrumentierung-Möglichkeiten

Für die Messung der Antwortzeit des Webservices, wird eine Instrumentierung sowohl auf dem Client, als auch auf dem Server durchgeführt. Die Instrumentierung erfolgt entweder durch:

  • Einfache Zeitaufnahme
start = System.nanoTime();

 /*
  *Codeabschnitt, der gemessen werden soll
  */

end = System.nanoTime();

oder durch:

  • Starten einer Transaktion mit Hilfe der ARM-Bibliothek
myTransaction.start();   //ARM-Bibliothek nimmt Zeitstempel und berechnet Antwortzeit

 /*
  *Codeabschnitt, der gemessen werden soll
  */

myTransaction.stop();    //ARM-Bibliothek stoppt die Berechnung der Antwortzeit

Clientseitige Instrumentierung

Vor dem Service-Aufruf wird ein ARM-Transaktion-Objekt erzeugt und die Transaktion gestartet. Aus dem Transaktion-Objekt wird dann einen Correlator erzeugt. Dieser wird dann der entsprechenden Service-Operation mit den zu verrechnenden Zahlen als Parameter übergeben. Nach dem Aufruf des Services wird die Transaktion gestoppt.

Um einen Gefühl des ARM-Overhead zu haben, kann auch den Service mit den zu verrechnenden Zahlen und einen "Null"-Objekt (an der Stelle des Correlators) als Parameter aufgerufen werden. Dabei erfolgt die Performancemessung ohne ARM(d.h. es wird kein Transaktion-Objekt erzeugt und keine Transaktion gestartet), stattdessen wird vor und nach dem Service-Aufruf die Zeit aufgenommen.

...

/**Initialisierung der Transaktion*/
ArmTransaction tran =  prepareTransaction("Client");

CalcClient callService = new CalcClient(); 
		
startTime = System.nanoTime();
    	 
/**Startet die Messung*/
tran.start();
    	 
/**Erzeugt den Korrelator*/
ArmCorrelator myCorr = tran.getCorrelator();
    	 
/**Service-Aufruf mit Correlator-Übergabe*/
callService.callCalc('*', 10000, 55000, myCorr.getBytes());
    	
/**Stoppt die Zeitmessung*/
tran.stop(ArmConstants.STATUS_GOOD);
         
endTime = System.nanoTime();

...

Serviceseitige Instrumentierung

Auf der Service-Seite wird im Fall einer ARM-Messung ebenfalls ein neues Transaktion-Objekt erzeugt. Die Transaktion wird dann mit dem übergebenen Correlator als Parameter vor der Durchführung der Berechnung gestartet. Durch den Correlator weiß dann ARM, dass die Messung auf der Client-Seite und die aus der Service-Seite zusammengehören und fasst die beiden Messungen in einem "Unit of Work" zusammen.

Wird der Service jedoch nur mit einem "Null"-Objekt aufgerufen, dann bedeutet dies, dass eine Messung ohne ARM durchzuführen ist. Vor und nach der Berechnung wird dann die Zeit aufgenommen. Die Operation returniert ein String-Array mit dem Ergebnis der Berechnung und die Antwortzeit.

public String[] multiplikation (double a, double b, byte[] corr){
	
	
	//ARM-Call
	startTime = System.nanoTime();

	/**Startet die Messung*/	
	mytran.start(corr);
        
        /**Die Berechnung wird durchgeführt*/
	result = a * b;

        /**Stoppt die Zeitmessung*/
	mytran.stop(ArmConstants.STATUS_GOOD);
		
	endTime = System.nanoTime();
		
	toReturn [0] =Double.toString(result);
	toReturn [1] =Long.toString(this.endTime-this.startTime);
	
        /**Gibt das Ergebnis dem Client zurückt*/
	return this.toReturn;
}

Die von der ARM-Bibliothek gemessene Zeit wird direkt von der Daemon-Anwendung armtcpd.exe in einer vorher erzeugten Datenbank-Tabelle gespeichert. Das tang-IT Management-Tool liefert hierfür zwei Scripts createDB.mysql und createDB.sqlite, womit eine MySQL- oder sqlite-Datenbank mit den benötigten Tabellen erzeugt werden kann. Es genügt also eine Transaktion zu starten und zu stoppen, und die ARM-Bibliothek speichert die gemessenen Daten in der Datenbank.


Parallele Service-Aufrufe

Batch-Datei für parallele Service-Aufrufe

@echo off
for /L %%i IN (1 1 100) do start/b java -Xmx10M -Xms3M -jar Myclient.jar
pause

Tests

Einmaliger Service-Auruf

  • Gemessene Antwortzeiten inklusive Arm-Overhead:
  Without ARM performed Calculation:
  1.230956*11.09834 = 13.661568213039999
  Requiered Time including ARM-Time(Service-Side):        0.085891 ms
  Requiered Time including ARM-Time(Client-Side):         488.636041 ms
  • Von ARM berechnete Antwortzeiten
  1. TransactionClient    485.846606 ms   GOOD    02.02.12 19:53:46
  2. TransactionService     0.010534 ms   GOOD    02.02.12 19:53:46
  • Gemessene Antwortzeiten ohne Arm
  Without ARM performed Calculation:
  1.230956*11.09834 = 13.661568213039999
  Without ARM requiered Time (Service-Side): 0.001215 ms
  Without ARM required Time (Client-Side): 696.668317 ms

Mit den Ergebnissen der Service-Seite kann man den ARM-Overhead berechnen:

 Auf der Service-Seite beträgt es 0.085891 - 0.001215 = 0,084676 ms


Mehrere parallele Service-Aufrufe

               Mit ARM berechnete Zeiten                                                Ohne ARM berechnete Zeiten

1. TransactionClient    2193.390681 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 6500.760055 ms
   TransactionService     0.007293 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 8.1E-4 ms
2. TransactionClient    2258.964882 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 6385.572809 ms
   TransactionService     0.010129 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 0.001216 ms
3. TransactionClient    2346.201871 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 5961.481897 ms
   TransactionService     0.007292 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 8.1E-4 ms
4. TransactionClient    2022.425678 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 6580.796372 ms
   TransactionService     0.007293 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 8.1E-4 ms
5. TransactionClient    2005.725938 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 6099.297395 ms
   TransactionService     0.007293 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 0.001215 ms
6. TransactionClient    1714.493555 ms  GOOD    03.02.12 10:58:58           Without ARM required Time (Client-Side): 6872.239027 ms
   TransactionService     0.007698 ms   GOOD    03.02.12 10:58:58           Without ARM requiered Time (Service-Side): 8.1E-4 ms
7. TransactionClient    1919.685753 ms  GOOD    03.02.12 10:58:59           Without ARM required Time (Client-Side): 6336.439053 ms
   TransactionService     0.008103 ms   GOOD    03.02.12 10:58:59           Without ARM requiered Time (Service-Side): 0.001215 ms
8. TransactionClient    2729.594181 ms  GOOD    03.02.12 10:59:01           Without ARM required Time (Client-Side): 6482.743994 ms
   TransactionService     0.007292 ms   GOOD    03.02.12 10:59:01           Without ARM requiered Time (Service-Side): 8.1E-4 ms
9. TransactionClient    2633.898945 ms  GOOD    03.02.12 10:59:01           Without ARM required Time (Client-Side): 6290.680573 ms
   TransactionService     0.007292 ms   GOOD    03.02.12 10:59:01           Without ARM requiered Time (Service-Side): 0.001215 ms
10. TransactionClient   2605.304504 ms  GOOD    03.02.12 10:59:01           Without ARM required Time (Client-Side): 6838.425486 ms
   TransactionService     0.007293 ms   GOOD    03.02.12 10:59:01           Without ARM requiered Time (Service-Side): 0.001216 ms
11. TransactionClient   2003.953421 ms  GOOD    03.02.12 10:59:01           Without ARM required Time (Client-Side): 7397.625111 ms
   TransactionService     0.007698 ms   GOOD    03.02.12 10:59:00           Without ARM requiered Time (Service-Side): 8.11E-4 ms
12. TransactionClient   3117.833665 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 6865.109256 ms
   TransactionService     0.007292 ms   GOOD    03.02.12 10:59:01           Without ARM requiered Time (Service-Side): 8.1E-4 ms
13. TransactionClient   3275.718102 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 7300.114819 ms
   TransactionService     0.006888 ms   GOOD    03.02.12 10:59:02           Without ARM requiered Time (Service-Side): 0.001216 ms
14. TransactionClient   2949.803950 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 6806.186346 ms
   TransactionService     0.007698 ms   GOOD    03.02.12 10:59:02           Without ARM requiered Time (Service-Side): 8.1E-4 ms
15. TransactionClient   3060.808867 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 7269.313949 ms
   TransactionService     0.005267 ms   GOOD    03.02.12 10:59:02           Without ARM requiered Time (Service-Side): 8.1E-4 ms
16. TransactionClient   2962.066928 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 7027.736745 ms
   TransactionService     0.007698 ms   GOOD    03.02.12 10:59:02           Without ARM requiered Time (Service-Side): 0.00162 ms
17. TransactionClient   2331.243857 ms  GOOD    03.02.12 10:59:02           Without ARM required Time (Client-Side): 7328.753015 ms
   TransactionService     0.008103 ms   GOOD    03.02.12 10:59:02           Without ARM requiered Time (Service-Side): 4.05E-4 ms

Um die gespeicherten ARM-Zeiten auszugeben, kann man mit tang-IT den Befehl armquery auf der Konsole ausführen. Dieser Befehl liefert alle in der Datenbank gespeicherte Transaktionen zurück. Es ist auch möglich die Daten zu sortieren oder nur die gewünschten Daten ausgeben zu lassen. Dafür gibt es verschiedene Standard- und Beschränkung-Optionen, die verwendet werden können.

Die hier oben ausgegebenen ARM-Zeiten wurden mit dem folgenden Befehl ausgegeben:

armquery.exe --sort-by start --result-max 40 --children ApplicationClient --start-from 03.02.12
  • --sort-by start : die Ergebnisse werden nach der Startzeit aufsteigend sortiert
  • --result-max 40 : beschränkt die Anzahl der gefundenen Daten auf 40
  • --children : bewirkt, dass die Daten möglichst nach der Beziehung Parent/Child ausgeben werden.
  • --start-from 03.02.12 : bewirkt, dass alle Transaktionen, die angezeigt werden, frühstens am 03.02.12 in die DB gespeichert wurden.

Fazit

Das Ziel dieses Projekts war eine Apache Axis2 Performance-Instrumentierung mit der ARM-Bibliothek und dem Management-Tool tang-IT. Dieses Ziel wurde erreicht. Die Instrumentierung wurde auf zwei verschiedene Weisen durchgeführt. Es wurde zunächst eine Instrumentierung mit der ARM-Bibliothek durchgeführt und dann eine Instrumentierung durch einfache Zeitaufnahme. Als Implementierung der ARM-Standards wurde das tang-IT Management-Tool verwendet. Mit diesem konnte man auch die gemessenen Zeiten managen.

Literatur

Mitgelieferter Quick Start Guide des "tang-IT ARM 4.0 Destop Kit"-Pakets [1]

Entwurf und Implementierung eines Ansatzes zur Performance-Instrumentierung der Apache Axis Umgebung

Eine generische Performance-Instrumentierung des JBoss Application Servers

Apache Axis