\chapter{Performance-Untersuchung} \label{ch:performance-checking} \section{Auswertung des Systems} \label{sec:performance-checking:system} \mytodos{Hier die Auswertung des Produktionsservers unterbringen} \section{Statistiken im PostgreSQL auswerten} \label{sec:performance-checking:postgresql-statistics} \mytodos{Logs auswerten, am besten vom Produktionsserver. Ebenfalls sollte man die Webseite prüfen, die den Cache von OpenJPE auswerten} \section{Überprüfung des PostgreSQL und Servers} \label{sec:performance-checking:postgresql-checking} \mytodos{Konfiguration vom Produktionsserver prüfen} \section{Einbau und Aktivieren von Performance-Messung} \label{sec:performance-checking:performance-measure} \mytodos{Einbau der Messungen direkt in die Webseite bzw. in ein Log} \mytodos{Einstellung am postgresql um die queries mit zu loggen} \section{Untersuchung der Anwendung} \label{sec:performance-checking:investigation-application} Nun werden die unterschiedlichen Schichten betrachtet und möglichen Performance-Verbesserungen untersucht und deren Vor"= und Nachteile herausgearbeitet. Für die Tests wird ein aktuelles Manjaro-System mit frisch installierten Payara als Serverhost und der IntelliJ IDEA als Entwicklungsumgebung verwendet. Der Computer ist mit einer Intel CPU i7-12700K, 32 GB Arbeitsspeicher und einer SSD als Systemfestplatte ausgestattet. Zur ersten Untersuchung und der Bestimmung der Basis-Linie, wurde das Script ohne eine Änderung an dem Code und der Konfiguration mehrfach aufgerufen. Hierbei hat sich gezeigt, dass der erste Aufruf nach dem Deployment ca. 1500 ms gedauert hat. Die weiteren Aufrufe dauert dann im Durchschnitt bei 600 ms. Beim achten Aufruf des Scripts hat der Server nicht mehr reagiert und im Log ist ein OutOfMemoryError protokolliert worden. Nach einem Neustart des Servers, konnte das gleiche Verhalten wieder reproduziert werden. Daraufhin wurde das Test-Script um die Anzeige der aktuellen Speicherverwendung des Payara-Servers erweitert und diese zeitgleich zu beobachten. Diese Auswertung zeigte, dass der Server mit ca. 1500 MB RSS Nutzung an seine Grenzen stößt. Diese Grenzen wurde durch die Konfigurationsänderung im Payara-Server von \texttt{-Xmx512m} auf \texttt{-Xmx4096m} nach oben verschoben. Nun werden ca. 60 Aufrufe des Scripts benötigt, damit der Server nicht mehr reagiert. Hierbei wird aber kein OutOfMemoryError in der Log-Datei protokolliert und der Server verwendet nun ca. 4700 MB RSS. Bei allen Tests war noch mehr als die Hälfte des verfügbaren Arbeitsspeichers unbenutzt. Dies zeigt direkt, dass es ein problem in der Freigabe der Objekte gibt, da dass erhöhen des verwendbaren Arbeitsspeicher das Problem nicht löst, sondern nur verschiebt. Als Grundlage für die Vergleiche wurden eine Messung durchgeführt, bei der alle Caches deaktiviert wurden und keine Änderung am Code vorgenommen wurde. Das Ergebnis dieser Messung ist in \ref{tab:MeasureWithoutCache} zu finden. Diese zeigen auch direkt ein erwartetes Ergebnis, dass der erste Aufruf bedeutend länger dauert als die Nachfolgenden. Ebenfalls sieht man eindeutig, dass die Anzahl der Anfragen nach dem ersten Aufruf immer die gleiche Anzahl besitzen. Der Speicherbedarf steigt auch relative gleichmässig, was nicht recht ins Bild passt, da hier keine Objekte im Cache gehalten werden sollten. \begin{table}[h!] \centering \begin{tabular}{|r|r|r|r|r|r|r|r|} \hline & \multicolumn{3}{|c|}{Aufrufzeit} & & \multicolumn{3}{|c|}{RSS} \\ \hline \# & min & avg & max & Queries & davor & danach & diff \\ \hline 1 & 395 & 578 & 1312 & 12237 & 747.15 & 924.88 & 177.73 \\ 2 & 353 & 375 & 464 & 12080 & 924.51 & 1027.75 & 103,24 \\ 3 & 286 & 345 & 535 & 12080 & 1018.21 & 1145.36 & 127.15 \\ 4 & 291 & 307 & 340 & 12080 & 1129.91 & 1239.75 & 109,84 \\ \hline \end{tabular} \caption{Messung ohne Caches} \label{tab:MeasureWithoutCache} \end{table} Vor jedem weiteren Test-Lauf wurde die Domain beendet und komplett neugestartet, um mit einer frischen Instanz zu beginnen. Hierbei ist aufgefallen, dass fast immer 62 Abfragen zur Startup-Phase dazugehört haben, unabhängig von den konfigurierten Cache Einstellungen. \subsection{Caching im OpenJPA} \label{sec:performance-checking:investigation-application:caching-openjpa} Die Cache-Einstellung von OpenJPA werden über die zwei Einstellungen \texttt{openjpa.DataCache} und \texttt{openjpa.QueryCache} konfiguriert. Bei beiden Einstellungen kann zuerst einmal über ein einfaches Flag \textit{true} und \textit{false} entschieden werden ob der Cache aktiv ist. Zusätzlich kann über das Schlüsselwort \textit{CacheSize} die Anzahl der Elementen im Cache gesteuert werden. Wird diese Anzahl erreicht, dann werden zufällige Objekte aus dem Cache entfernt und in eine SoftReferenceMap übertragen. Zuerst wird mit aktivierten Cache mit einer Cache-Größe von 1000 Elemente getestet. Wie in \ref{tbl:MeasureOJPAactive} zu sehen, dauert auch hier der erste Aufruf minimal länger als ohne akivierten Cache. Alle Nachfolgenden Aufrufe wiederrum sind um 100ms schneller in der Verarbeitung. Auch bei der Anzahl der Anfragen an die Datenbank kann mehr den Rückgang der Anfragen sehr gut sehen. Aktuell kann die Verringerung des wachsenden Speicherbedarfs nur nicht erklärt werden. \begin{table}[h!] \centering \begin{tabular}{|r|r|r|r|r|r|r|r|} \hline & \multicolumn{3}{|c|}{Aufrufzeit} & & \multicolumn{3}{|c|}{RSS} \\ \hline \# & min & avg & max & Queries & davor & danach & diff \\ \hline 1 & 277 & 469 & 1506 & 7206 & 764,21 & 859.96 & 95.75 \\ 2 & 228 & 269 & 384 & 6767 & 848,64 & 908,44 & 59.80 \\ 3 & 224 & 238 & 299 & 6656 & 898.71 & 949.94 & 51.23 \\ 4 & 214 & 235 & 325 & 6671 & 936.70 & 999.49 & 62.79 \\ \hline \end{tabular} \caption{Messung mit OpenJPA-Cache und Größe auf 1000} \label{tbl:MeasureOJPAactive} \end{table} Bei einer erhöhten Cache-Größe, zeigt sich auf den ersten Blick ein noch besseres Bild ab, wie in \ref{tbl:MeasureOJPAactivebigger} ersichtlich ist. Der erste Aufruf entspricht der Laufzeit mit geringerer Cache-Größe, aber schon die Anfragen an die Datenbank gehen drastisch zurück. Bei den weiteren Aufrufen werden im Schnitt nun nur noch 6 Anfragen pro Seitenaufruf an die Datenbank gestellt, wodurch die Laufzeit im Schnitt nochmal um 100 ms beschleunigt werden konnte. \begin{table}[h!] \centering \begin{tabular}{|r|r|r|r|r|r|r|r|} \hline & \multicolumn{3}{|c|}{Aufrufzeit} & & \multicolumn{3}{|c|}{RSS} \\ \hline \# & min & avg & max & Queries & davor & danach & diff \\ \hline 1 & 178 & 347 & 1507 & 1419 & 752.10 & 862.38 & 110,28 \\ 2 & 126 & 152 & 232 & 60 & 853.72 & 875.21 & 21.49 \\ 3 & 130 & 134 & 142 & 60 & 880.08 & 880.94 & 0,86 \\ 4 & 125 & 128 & 135 & 60 & 865.36 & 897.96 & 32.60 \\ \hline \end{tabular} \caption{Messung mit OpenJPA-Cache und Größe auf 10000} \label{tbl:MeasureOJPAactivebigger} \end{table} \mytodos{pin und unpin noch mit einbringen? SoftReferenceMap nochmal genau durchleuchte, laut doku entfällt dort nichts wenn kein Timeout auf der Klasse definiert ist} \mytodos{kurzes Fazit fehlt noch!} \subsection{Caching im \ac{JPA}} \label{sec:performance-checking:investigation-application:caching-jpa} Die Cache-Einstellungen von \ac{JPA} werden über mehrere Einstellungen konfiguriert. Anhand von \texttt{eclipselink.query-results-cache} wird definiert, dass die Ergebnisse von benannten Abfragen im Cache gespeichert werden. Für den Zugriff in den Cache, wird neben den Namen noch die übergebenen Parameter berücksichtigt. % https://eclipse.dev/eclipselink/documentation/2.5/concepts/cache008.htm Der geteilte Cache, der für die Dauer der persistenten Einheit (EntityManagerFactory oder der Server) vorhanden ist, kann über \texttt{eclipselink.cache.shared.default} gesteuert werden. Dieser kann nur aktiviert oder deaktiviert werden. % https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching Mit \texttt{eclipselink.cache.size.default} wird die initiale Größe des Caches definiert, hierbei ist der Standardwert 100. Die Objekt werden nicht direkt aus dem Cache entfernt, sondern erst nachdem der \ac{GC} diese freigeben hat. Zusätzlich wird über \texttt{eclipselink.cache.type.default} die Art des Caching gesteuert. Die Einstellung mit dem höchsten Speicherbedarf ist \textit{FULL}, bei dem alle Objekte im Cache bleiben, außer sie werden explizit gelöscht. Die Einstellung \textit{SOFT} und \textit{WEAK} sind sehr ähnlich, der unterschied ist die Referenzierung auf die Entität. Bei \textit{WEAK} bleiben die Objekte nur solange erhalten, wie die Anwendung selbst eine Referenz auf die Objekte fest hält. Im Gegensatz dazu bleibt bei \textit{SOFT} die Referenz so lange bestehen, bis der \ac{GC} wegen zu wenig Speicher Objekte aus dem Cache entfernt. % https://eclipse.dev/eclipselink/documentation/2.5/concepts/cache002.htm Um den Cache zu deaktivieren wurden beiden Einstellungen auf \textit{false} gestellt, die Größe auf 0 und der Cache-Typ auf \textit{NONE}. Hierbei lag die maximale gemessene Laufzeit des ersten Aufrufs bei ca. 1300 ms und es wurden 12219 Abfragen an die Datenbank gestellt. Bei den nachfolgenden Aufrufe lag die Aufrufzeit im Durchschnitt bei 350 ms und 12080 Abfragen. Um den Cache wieder zu aktivieren wurden die Einstellungen auf \textit{true} gestellt, die Größe auf den Standardwert von 100 und der Cache-Type auf \textit{SOFT} gestellt. Hierbei wurde eine maximale Laufzeit beim ersten Aufruf ebenfalls von 1300 ms gemessen und es wurden 12218 Abfragen abgesetzt. Bei den nachfolgenden Aufrufen lag die Aufrufzeit im Durchschnitt bei 340 ms. Bei WEAK hat sich die Speichernutzung nur um 5MB gesteigert \mytodos{in einer Tabelle oder Graphen darstellen?} Wie man an den Daten erkennen kann, wird der Cache vom \ac{JPA} für diese Abfrage nicht verwendet, sonst müssten die Anzahl der Abfragen an die Datenbank drastisch reduziert werden. Selbst die Laufzeit ändert sich nur marginal. \subsection{Caching in \ac{EJB}} \label{sec:performance-checking:investigation-application:caching-ejb} Die Cache-Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Servers zu erreichen. Hier \begin{table}[h!] \centering \begin{tabular}{|r|r|r|r|r|r|r|r|} \hline & \multicolumn{3}{|c|}{Aufrufzeit} & & \multicolumn{3}{|c|}{RSS} \\ \hline \# & min & avg & max & Queries & davor & danach & diff \\ \hline 1 & 416 & 554 & 1269 & 12237 & 840.31 & 998.07 & 157.76 \\ 2 & 299 & 394 & 749 & 12080 & 973.20 & 1101.37 & 128.17 \\ 3 & 293 & 324 & 382 & 12080 & 1092.00 & 1192.87 & 100.87 \\ 4 & 281 & 318 & 398 & 12080 & 1191.25 & 1305.29 & 114.04 \\ \hline \end{tabular} \caption{Messung mit OpenJPA-Cache und Größe auf 10000} \label{tbl:MeasureEJBAactive} \end{table} \subsection{Abfragen JPQL} \label{sec:performance-checking:investigation-application:query-jpql} \subsection{Abfragen Criteria API} \label{sec:performance-checking:investigation-application:query-criteria-api} \subsection{materialized views} \label{sec:performance-checking:investigation-application:materialized-views} \subsection{cached queries} \label{sec:performance-checking:investigation-application:cached-query} \subsection{Umgestalten der Datenbanktabellen} \label{sec:performance-checking:investigation-application:new-table} \subsection{Verkleinerung der Abfragen} \label{sec:performance-checking:investigation-application:smaller-query}