Daily CheckIn

This commit is contained in:
marcodn 2024-09-12 23:02:22 +02:00
parent 0e8b521f17
commit 08647e4632
12 changed files with 169 additions and 33 deletions

View file

@ -5,23 +5,24 @@
%*******************************************************
% If problems with the headers: get headings in appendix etc. right
%\markboth{\spacedlowsmallcaps{Appendix}}{\spacedlowsmallcaps{Appendix}}
\chapter{JSF Performance Measure}
\label{ap:jsf_performance_measure}
\chapter{JSF Performance Statistics Servlet}
\label{ap:jsf_performance_statistics_servlet}
Für die Protokollierung der Abläufe im \ac{JSF} werden zwei Klassen benötigt. Die Factory \ref{lst:logger_factory},
wird die Wrapper"=Klasse in die Bearbeitungsschicht eingeschleust. Diese Wrapper"=Klasse \ref{lst:logger} beinhaltet
dann die eigentliche Performance-Messung, inklusive der Ausgabe in die Log"=Datei des \textit{Glassfish}"=Servers.
Zusätzlich muss in der Konfiguration \textbf{faces-config.xml} noch angepasst werden, wie in
\ref{lst:logger_factory_activate}, um die Factory durch das System aufrufen zu lassen.
Um die Cache-Informationen über einen \ac{API}"=Aufruf bereitzustellen, wird ein Servlet \ref{lst:servlet} und ein
Provider \ref{lst:servlet_provider} benötigt. Für die Aufnahme in der Routing, wird noch ein zusätzlicher Eintrag in
der \textit{web.xml} benötigt \ref{lst:servlet_activate}.
\includecode[java]{chapters/thesis/appendix05_Logger.java}{lst:logger}{Vdi Logger}
\includecode[java]{chapters/thesis/appendix05_LoggerFactory.java}{lst:logger_factory}{Vdi Logger Factory}
\includecode[java]{chapters/thesis/appendix05_servlet.java}{lst:servlet}{Performance Statistics Servlet}
\includecode[java]{chapters/thesis/appendix05_provider.java}{lst:servlet_provider}{Performance Statistics Provider}
\begin{lstlisting}[language=xml,caption={Einbindung Factory},label=lst:logger_factory_activate]
<factory>
<view-declaration-language-factory>
de.wedekind.utils.VdlLoggerFactory
</view-declaration-language-factory>
</factor>
\begin{lstlisting}[language=xml,caption={Einbindung Servlet},label=lst:servlet_activate]
<servlet>
<servlet-name>PerformanceStatisticServlet</servlet-name>
<servlet-class>de.wedekind.servlets.PerfStatServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>PerformanceStatisticServlet</servlet-name>
<url-pattern>/api/perfstat</url-pattern>
</servlet-mapping>
\end{lstlisting}

View file

@ -0,0 +1,41 @@
public interface PerfStatistics {
String getOpenJPAStatistics();
String getEntityClasses();
}
@Stateless
public class PerfStatisticsImpl implements PerfStatistics {
@Inject
private EntityManagerJPAFactory entityManagerFactory;
private OpenJPAEntityManagerFactory openJPAEntityManagerFactory;
@PostConstruct
public void init() {
openJPAEntityManagerFactory = OpenJPAPersistence.cast(entityManagerFactory.getEntityManager().getEntityManagerFactory());
}
@Override
public String getOpenJPAStatistics() {
StoreCache cache = openJPAEntityManagerFactory.getStoreCache();
CacheStatistics st = cache.getStatistics();
return String.format("{ \"ReadCount\": %d, \"HitCount\": %d, \"WriteCount\": %d }", st.getReadCount(), st.getHitCount(), st.getWriteCount());
}
@Override
public String getEntityClasses() {
StringBuilder res = new StringBuilder("{ \"Entities\": [");
EntityManagerFactory emf = openJPAEntityManagerFactory;
EntityManager em = emf.createEntityManager();
Cache cache = emf.getCache();
for(EntityType<?> entityType : em.getMetamodel().getEntities()) {
Class<?> cls = entityType.getBindableJavaType();
res.append(String.format("\"%s\", ", cls.getCanonicalName()));
}
res.append("\"\"], \"Cache\": \"");
res.append(cache.toString());
res.append("\" }");
return res.toString();
}
}

View file

@ -0,0 +1,25 @@
public class PerfStatServlet extends HttpServlet {
private final static Logger m_Logger = Logger.getLogger(PerfStatServlet.class.toString());
@Inject
private PerfStatistics perfStatistics;
public PerfStatServlet() {
m_Logger.info("PerfStatServlet() Constructor");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String openJPAStatistics = perfStatistics.getOpenJPAStatistics();
String entityClasses = perfStatistics.getEntityClasses();
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType(MediaType.APPLICATION_JSON);
PrintWriter out = resp.getWriter();
out.print("{ \"openJPAStatistics\": ");
out.print(openJPAStatistics);
out.print(", \"entityClasses\": ");
out.print(entityClasses);
out.print(" }");
}
}

View file

@ -0,0 +1,27 @@
% !TeX root = ../../thesis.tex
%********************************************************************
% Appendix
%*******************************************************
% If problems with the headers: get headings in appendix etc. right
%\markboth{\spacedlowsmallcaps{Appendix}}{\spacedlowsmallcaps{Appendix}}
\chapter{JSF Performance Measure}
\label{ap:jsf_performance_measure}
Für die Protokollierung der Abläufe im \ac{JSF} werden zwei Klassen benötigt. Die Factory \ref{lst:logger_factory},
wird die Wrapper"=Klasse in die Bearbeitungsschicht eingeschleust. Diese Wrapper"=Klasse \ref{lst:logger} beinhaltet
dann die eigentliche Performance-Messung, inklusive der Ausgabe in die Log"=Datei des \textit{Glassfish}"=Servers.
Zusätzlich muss in der Konfiguration \textbf{faces-config.xml} noch angepasst werden, wie in
\ref{lst:logger_factory_activate}, um die Factory durch das System aufrufen zu lassen.
\includecode[java]{chapters/thesis/appendix06_Logger.java}{lst:logger}{Vdi Logger}
\includecode[java]{chapters/thesis/appendix06_LoggerFactory.java}{lst:logger_factory}{Vdi Logger Factory}
\begin{lstlisting}[language=xml,caption={Einbindung Factory},label=lst:logger_factory_activate]
<factory>
<view-declaration-language-factory>
de.wedekind.utils.VdlLoggerFactory
</view-declaration-language-factory>
</factor>
\end{lstlisting}

View file

@ -14,23 +14,37 @@ auf mögliche Optimierungen untersucht und bewertet.
Für die Untersuchung des Systems wird der direkte Zugang zum Server benötigt. Hierbei werden zuerst die im Kapitel
\ref{sec:basics:services} beschriebenen Einstellungen überprüft.
Zuerst wird am PostgreSQL"=Server die Konfiguration der Speicher mit der Vorgabe für Produktivsystem abgeglichen.
Zuerst wird am PostgreSQL"=Server die Konfiguration der Speicher mit der Vorgabe für Produktivsysteme abgeglichen.
Hierunter fallen die Einstellungen für die \textit{shared\_buffers}, der bei einem Arbeitsspeicher von mehr als 1 GB
circa 25\% des Arbeitsspeicher definiert sein soll \cite{PostgresC20.4:2024}.
circa 25\% des Arbeitsspeicher besitzen sollte \cite{PostgresC20.4:2024}.
\mytodos{die anderen Speicher abarbeiten?}
Bei der Einstellung \textit{temp\_buffers} geht es um den Zwischenspeicher für jede Verbindung, die bei der Verwendung
von temporären Tabellen verwendet wird. Dieser Wert sollte auf dem Standardwert von 8 MB belassen werden. Und nur bei
der Verwendung von großen temporären Tabellen verändert werden.
Der Speicher, der für eine Abfrage verwendet werden darf, wird über die Konfiguration \textit{work\_mem} gesteuert.
Wenn der Speicher zu gering wird, werden die Zwischenergebnisse in temporäre Dateien ausgelagert. Der empfohlene Wert
berechnet sich aus \textit{shared\_buffers} dividiert durch \textit{max\_connections} \citep{ConfigTo12:online}.
Sollte der Berechnung außerhalb der Grenzwerte von 1 MB und 256 MB liegen, ist der jeweilige Grenzwert zu verwenden.
Um zu ermitteln, ob die Konfiguration richtig ist, muss im PostgreSQL die Einstellung \textit{log\_temp\_files} auf 0
gesetzt werden. Mit dieser kann ermittelt, ob temporäre Dateien verwendet werden und deren Größe. Bei vielen kleineren
Dateien sollte der Grenzwert erhöht werden. Bei wenigen großen Dateien ist es ist sinnvoll den Wert so zu belassen.
Für die Wartungsaufgaben wie VACUUM oder dem erstellen von Indexen wird die Begrenzung über die Einstellung
\textit{maintenance\_work\_mem} gesetzt. Dieser Wert sollte 5\% des verfügbaren Arbeitsspeicher entsprechen und größer
als \textit{work\_mem} sein.
Dann wird mit dem Systemtools, wie den Konsolenanwendungen \textit{htop} und \textit{free}, die Auslastung des Servers
überprüft. Hierbei ist die CPU-Leistung, der aktuell genutzte Arbeitsspeicher, sowie die Zugriffe auf die Festplatte
überprüft. Hierbei ist die CPU"=Leistung, der aktuell genutzte Arbeitsspeicher, sowie die Zugriffe auf die Festplatte
die wichtigen Faktoren zur Bewertung.
Die CPU-Leistung sollte im Schnitt nicht die 70\% überschreiten, für kurze Spitzen wäre dies zulässig. Da sonst der
Die CPU"=Leistung sollte im Schnitt nicht die 70\% überschreiten, für kurze Spitzen wäre dies zulässig. Da sonst der
Server an seiner Leistungsgrenze arbeitet und dadurch es nicht mehr schafft die gestellten Anfragen schnell genug
abzuarbeiten.
Da unter Linux der Arbeitsspeicher nicht mehr direkt freigegeben wird, ist hier die Page-Datei der wichtigere Indikator.
Da unter Linux der Arbeitsspeicher nicht mehr direkt freigegeben wird, ist hier die Page"=Datei der wichtigere Indikator.
Wenn dieses in Verwendung ist, dann benötigen die aktuell laufenden Programme mehr Arbeitsspeicher als vorhanden ist,
wodurch der aktuell nicht verwendete in die Page-Datei ausgelagert wird. Hierdurch erhöhen sich die Zugriffszeiten auf
wodurch der aktuell nicht verwendete in die Page"=Datei ausgelagert wird. Hierdurch erhöhen sich die Zugriffszeiten auf
diese Elemente drastisch.
Die Zugriffsgeschwindigkeit, die Zugriffszeit sowie die Warteschlange an der Festplatte zeigt deren Belastungsgrenze auf.
@ -58,8 +72,8 @@ abgelaufen ist. Ebenso wird nach Standorten sortiert, um zu prüfen mit welchen
\mytodos{Hier noch mehr Infos dazu, für was genau die Editoren diese tun}
Da die Daten in der 3. Normalform in der Datenbank gespeichert werden, sind einige Relationen für die Abfragen
notwendig. Dies wird durch die generische Abfrage in \autoref{lst:documentlist} gezeigt. Zusätzlich wird für jedes
dargestellte Dokument eine zusätzliche Abfrage durchgeführt, die in \autoref{lst:documentlist_sub} zeigt, dass auch hier
notwendig. Dies wird durch die generische Abfrage in \ref{lst:documentlist} gezeigt. Zusätzlich wird für jedes
dargestellte Dokument eine zusätzliche Abfrage durchgeführt, die in \ref{lst:documentlist_sub} zeigt, dass auch hier
weitere Relationen notwendig sind.
\includecode[SQL]{chapters/thesis/chapter03_documentlist.sql}{lst:documentlist}{Generische Abfrage der Dokumentenliste}
@ -104,7 +118,7 @@ welchen Umfang die Umstellungen eine Veränderung im Verhalten der Webseite bewi
Bei den \ac{JSF} wird eine Zeitmessung eingefügt. Hierfür wird eine \textit{Factory} eingebaut, die sich in die
Verarbeitung der Seiten einhängt, und damit die Zeiten für das Ermitteln der Daten, das Zusammensetzen und das
Render der Sicht aufgenommen werden können. Die Zeiten werden in die Log°=Datei des \textit{Glassfish}!=Servers
Render der Sicht aufgenommen werden können. Die Zeiten werden in die Log"=Datei des \textit{Glassfish}"=Servers
hinterlegt und durch das Skript ausgewertet. Somit ist es einfach aufzuzeigen, an welcher Stelle der größte Teil
der Verzögerung auftritt.

View file

@ -17,6 +17,23 @@ prüfen, die den Cache von OpenJPE auswerten}
\section{Überprüfung des PostgreSQL und Servers}
\label{sec:performance-checking:postgresql-checking}
Die einfachste Art die Einstellungen zu prüfen ist, die Abfrage in \ref{lst:postgresql-select-settings} am
Datenbankserver auszuführen.
\begin{lstlisting}[language=SQL,caption={Ermitteln der PostgreSQL Einstellungen},label=lst:postgresql-select-settings]
SELECT name AS setting_name
, setting AS setting_value
, unit AS setting_unit
FROM pg_settings
WHERE name IN (
'shared_buffers'
, 'temp_buffers'
, 'work_mem'
, 'max_connections'
, 'maintenance_work_mem'
)
\end{lstlisting}
\mytodos{Konfiguration vom Produktionsserver prüfen}
\section{Einbau und Aktivieren von Performance-Messung}
@ -61,6 +78,9 @@ log_rotation_size = 100MB
wichtigste Einstellung ist \textit{log\_min\_duration\_statement}, diese definiert ab welcher Laufzeit eine Abfrage
protokolliert werden soll. Mit dem Wert 0 werden alle Abfragen protokolliert. Alle weitere Einstellungen sind so
gesetzt, dass nicht unnötige Abfragen für die spätere Auswertung mit \textit{pgBadger} protokolliert werden.
Zusätzlich ist die Einstellung \textit{log\_temp\_files} auf 0 zu setzen. Dadurch werden alle erzeugten temporären
Dateien und ihre Größe ebenfalls protokolliert. Diese Dateien entstehen, wenn der temporäre Puffer für die Abfrage
nicht ausreicht und die Zwischenergebnisse ausgelagert werden müssen.
\begin{lstlisting}[language=yaml,caption={PostgreSQL Ausgabekonfiguration},label=lst:postgresql_logconf]
log_min_duration_statement = 0
@ -74,6 +94,6 @@ log_error_verbosity = default
log_hostname = on
log_lock_waits = on
log_statement = 'none'
log_temp_files = -1
log_temp_files = 0
log_timezone = 'Europe/Berlin'
\end{lstlisting}

View file

@ -257,7 +257,7 @@ abfragt.
\label{tbl:measure-cached-queries}
\end{table}
\section{Caching im \ac{JPA}}
\section{Caching im JPA}
\label{sec:performance-investigation-application:caching-jpa}
%hier ein test vom acf: \acf{JPA}. aber ich seh ihn nicht
@ -301,7 +301,7 @@ abfragt.
%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.
\section{Caching in \ac{EJB}}
\section{Caching in EJB}
\label{sec:performance-investigation-application:caching-ejb}
Die Cache-Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Servers zu erreichen. Hier
@ -327,7 +327,7 @@ Die Cache-Einstellungen des \ac{EJB} sind in der Admin-Oberfläche des Payara-Se
\label{tbl:measure-ejb-cache-active}
\end{table}
\section{Abfragen \ac{JPQL}}
\section{Abfragen JPQL}
\label{sec:performance-investigation-application:query-jpql}
Für die \ac{JPQL} wird ein \ac{SQL} ähnlicher Syntax verwendet um die Abfragen an die Datenbank durchzuführen. Für die
@ -579,7 +579,8 @@ CREATE INDEX idx_searchdocument_startdate
CREATE INDEX idx_searchdocument_addressees_first_entry
ON searchdocument
(((addressees->0->>'surname')::text), ((addressees->0->>'firstname')::text));
( ((addressees->0->>'surname')::text)
, ((addressees->0->>'firstname')::text));
CREATE INDEX idx_searchdocument_city
ON searchdocument (city);
@ -650,8 +651,6 @@ Nach dem Anpassungen haben sich dann die Werte aus \ref{tbl:measure-materialized
\label{tbl:measure-materialized-view-ext}
\end{table}
\mytodos{prüfen ob ms oder msec die richtige SI-Einheit ist}
Da bei der Materialized View das laden der Daten und das wandeln in die Java"=Objekte getrennt programmiert wurde,
können hier eigene Zeitmessungen für die zwei Schritte eingebaut werden. Hierfür wird die Zeit vor dem
\textit{map}"=Aufruf und der \textit{map}"=Aufruf gemessen. Für den ersten Aufruf, wurde ein \textit{SearchDocument}

View file

@ -54,6 +54,15 @@
urldate = {2024-03-27}
},
@online{ConfigTo12:online,
author = {},
title = {Config - Too small work\_mem · pganalyze},
url = {https://pganalyze.com/docs/checks/settings/work_mem},
month = {},
year = {},
urldate = {2024-09-12}
},
@online{AspNetCore:2024:MVC,
year = 2024,
url = {https://learn.microsoft.com/de-de/aspnet/core/fundamentals/middleware/?view=aspnetcore-8.0},

Binary file not shown.

View file

@ -102,7 +102,7 @@
\include{chapters/thesis/appendix03}
\include{chapters/thesis/appendix04}
\include{chapters/thesis/appendix05}
%\include{chapters/examples/appendix02}
\include{chapters/thesis/appendix06}
%*************************************************************************
% Other Stuff in the Back
%*************************************************************************