Beliebte Suchanfragen
|
//

Freemarker Template Caching – Analyse eines Struts2 Performance Problems

4.2.2011 | 2 Minuten Lesezeit

Bei der Durchführung von Lasttests auf einem Projekt bemerkte ich einen spontanen Abfall der Antwortzeiten. Je mehr Benutzer auf die Anwendung zugriffen, desto langsamer wurde sie. Die Anwendung wurde mit dem Struts 2 Java Framework erstellt und griff auf die Datenbank über Hibernate zu. Eigentlich eine ganz simple Anwendung, umso verwunderlicher waren für mich die schlechten Ergebnisse. Nach dem Studium der von AppDynamics aufgezeichneten Messwerte wurde mir aber schnell klar, dass es sich um ein Problem mit Freemarker, der in Struts2 nutzbaren Template Engine, handeln musste:

Alle HotSpots gingen auf freemarker.cache.URLTemplateLoader.getURL() zurück, welches die abstrakte Definition einer in im Struts org.apache.struts2.views.freemarker.StrutsClassTemplateLoader implementierten Methode ist.

Also, was verursacht diese langen Wartezeiten? AppDynamics hat dankenswerterweise automatisch einige Threaddumps für uns gezogen, welche alle auf die blockierten Threads in sun.misc.URLClassPath.getLoader() hinweisen.


Schaut man sich den Source Code davon an, erkennt man dass dieser Code auf die URLClassPath Instanz synchonisiert ist.

private synchronized Loader getLoader(int index) {

Eigentlich hatte ich nicht erwartet, dass dies ein Engpass sein könnte, doch ich fand einige Threads, welche ebenfalls dieses Lock nutzten, aber es für Classloading verwendeten. Dieses war leider durch Speicherallokation im Betriebssystem erheblich gebremst.

Die Art wie Freemarker/Struts2 Templates laden ist also bei genauer Betrachtung gar nicht falsch. Dennoch wird offensichtlich unnötig oft auf diese Ressourcen zugegriffen.

Normalerweise verändern sich Templates nicht sehr häufig, weswegen sich Caching besonders anbieten würde. Und in der Tat gibt es die Möglichkeit in Freemarker Templates für eine Zeit zu cachen:

template_update_delay=60000

Diese Einstellung kann man in Struts über eine Datei namens freemarker.properties vornehmen. Laut der Dokumentation von Struts wird der eingestellte Wert als die Anzahl von Sekunden verwendet, welche ein Template im Cache sein muss bevor es auf Aktualität überprüft wird. Also sollte dieser Wert hoch gewählt werden.

Die Dokumentation empfiehlt ferner eine Einstellung namens struts.freemarker.templatesCache, welche auf true gesetzt werden soll. Angeblich sei es notwendig die Templates aus dem Classpath in das Filesystem zu kopieren, da Freemarker andernfalls nicht korrekt das Änderungsdatum bestimmen könne. Auf den von mir getesteten aktuellen JVMs funktionierte dies jedoch tadellos.

template_update_delay hat für das von mir getestete Projekt wunderbar funktioniert, dennoch frage ich mich warum überhaupt Templates erneut gelesen werden sollten. Auf echten Produktionssystemen würde ein einmaliges Laden völlig ausreichen. Zumal die Prüfung in freemarker.cache.TemplateCache mit nicht unerheblich viel Code verbunden ist.

Ich denke, es lohnt sich über eine eigene Implementierung der Klasse org.apache.struts2.views.freemarker.FreemarkerManager nachzudenken. Sie verbindet Struts2 mit Freemarker und versucht in der Standardimplementierung das Template zweimal aus dem Dateisystem zu lesen bevor der Classpath verwendet wird. Dieses Verhalten bietet zwar einige Flexibilität zur Entwicklungszeit, verursacht aber in Produktion unnötige Wartezeiten.

Nach der Veränderung der „Cache“-Einstellung verschwanden die HotSpots und die Anwendung lief deutlich schneller. Insbesondere der Classloader war kein Engpass mehr.

|

Beitrag teilen

//

Weitere Artikel in diesem Themenbereich

Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.

//

Gemeinsam bessere Projekte umsetzen.

Wir helfen deinem Unternehmen.

Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.

Hilf uns, noch besser zu werden.

Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.