CachingServlet im Detail

Als Grundvoraussetzungen für die Entwicklung des CachingServlets standen Stabilität und Performancesteigerung im Vordergrund.

EH-Cache: The Most Widely Used Java Cache

Stabilität erreichten wir durch die Minimierung der Requests, die an Helma weitergereicht werden, Performance durch Caching. Als Cache-Engine verwenden wir EH-Cache. Dieses großartige Stück Software ist nicht nur beim Caching im Einsatz, wir verwenden es bei den verschiedensten rechen- oder zeitaufwändigen Dingen.

Funktionsweise

Als erster Schritt wird überprüft, ob eine im Request angeforderte HTML-Seite bereits in einer gültigen, gecachten Version vorhanden ist. Im Idealfall, der bei uns in mehr als 90% der Fälle zutrifft, liefert das CachingServlet dafür direkt die gecachte Version aus dem Speicher zurück.

Ist ein Cache-Eintrag nicht mehr up to date, wird der erste Request, der diese Seite anforderte, zur Helma-Applikation durchgelassen, um so den Cacheeintrag zu erneuern. Alle weiteren werden in der Zwischenzeit mit der bereits vorhandenen Version beliefert. Erst nachdem der erste Request aus der Applikation zurückkehrt, werden alle nachfolgenden Requests mit der neuesten Version beliefert.

Sollte es noch keinen Cache-Eintrag geben, wird ebenfalls nur ein Request durchgelassen. In diesem Fall müssen jedoch die Folgerequests warten, bis der erste Request abgeschlossen wurde. Anschließend wird dessen Ergebnis auch an alle anderen, bis dahin wartenden Requests ausgeliefert und als Cache-Eintrag abgelegt.

Was und wie wird gecached?

Wir cachen sowohl die unkomprimierte Rohfassung, als auch die fertig komprimierte Version einer Response. Durch diese Vorgangsweise erreichten wir die effizienteste Möglichkeit um Seiten auszuliefern. Im Idealfall werden so alle Requests gecached.

Da es immer Teile einer Website gibt, die nicht – oder unterschiedlich lange – gecached werden dürfen, gibt es hierfür die Möglichkeit der Konfiguration:

Für jeden HTTP-Response-Code kann man getrennt festlegen, wie lange eine Seite im Cache verweilt. Zum Beispiel kann man ein „404 Not Found“ für kürzere Zeit cachen, ein „301 Moved Permanently“ umso länger.

Für „HTTP 200 OK“ Responses kann man über regular Expressions aufgrund ihrer URL getrennt festlegen, ob und wie lange diese Seiten ihre Gültigkeit behalten.

Den Überblick bewahren

Natürlich will man nicht nur oberflächliche Effizienz, man benötigt auch Kontrolle, um diese Effizienz überprüfen zu können. Für diese Zwecke gibt es eine simple Schnittstelle. Über eine geschützte Adresse erhält man dann folgende Auswertung:

=== STATISTICS ===

Cache hits:		569334
Cache misses:		25596
Cache hit rate:		96%
Elements in cache:	2946
Elements in memory:	1500
Elements on disk:	1500
Average retrieval:	0.048412707 ms
Evictions:		0
Hits in memory:		520782
Hits on disk:		48552
Requestqueue size:	0

=== CONFIGURATION EH-Cache ===

Name:				default
Enabled:			true
Disk store path:		/fs/path/...
Disk persistent:		true
Overflow to disk:		true
Max. elements in memory:	1500
Max. elements on disk:		1500
Disk spool buffer:		30 MB

=== CONFIGURATION servlet ===

Enabled:		true
maxQueueSize:		4000
blockingTimeout(URL):	5000 (http://...)
Update EHcache-config:	false

Adminadresses:

Responsecode-TTL-values:
	307 -> 600
	404 -> 60
	303 -> 600
	500 -> 0
	302 -> 600
	301 -> 3600

URL-Part-exclusions:

Cachetime-mappings:
	"^/helma/xxxxx/_.*" -> -1
	"^.*$" -> 20

Man sieht hier auch die derzeit gültigen Konfigurationsparameter, die wir hier beispielhaft mit auflisten. Unterschiedliche Response-Codes werden unterschiedlich lange gecached. Alle „200 OK“-Antworten werden noch über eine oder mehrere regulärer Ausdrücke einer Cache-Time zugewiesen.

Munin zur Erstellung von Graphen leicht gemacht

Um das ganze noch abzurunden gibt es wichtige Kennzahlen auch noch als maschinenlesbares Format, um Graphen wie wir sie hier in diesem Artikel verwenden zu erzeugen. Das sieht dann wie Folgt aus:

total.value 600766
hits.value 574691
misses.value 26075
hitRate.value 96
memoryElements.value 1500
diskElements.value 1500
retrievalAvg.value 0.048760116
queueSize.value 0

Manfred Andres,