Artikel

Dezember 2005 | Artikel

Kurze Wege zum Ziel

(Link zum Artikel: http://www.it-republik.de/dotnet/artikel/0782)

Der Caching Application Block der Enterprise Library 1.0 im Detail

Text: von Stefan Zill
  • Teilen
  • kommentieren
  • empfehlen
  • Bookmark and Share
Je höher die Anforderungen an eine Anwendung im Bereich Performance und Skalierbarkeit sind, desto wichtiger ist es, bereits bei deren Design und Implementierung entsprechende Caching-Mechanismen einzuplanen. Für ASP.NET-Applikationen bietet das .NET Framework bereits Caching-Unterstützung an - der Caching Application Block der Enterprise Library liefert darüber hinausgehende Unterstützung auch für Windows-Forms-Anwendungen und zusätzliche Funktionalitäten.

Im Rahmen der Artikelserie [1] zum Thema Microsoft Enterprise Library 1.0 (kurz: EntLib) geht es in dieser Folge um den Caching Application Block. Im Juli 2005 erschien die Version 1.1 der Enterprise Library [2]. Sie ist funktional identisch mit der Version 1.0 und beinhaltet lediglich Fehlerbehebungen. Daher geht dieser Artikel nicht explizit auf die beiden Versionen ein.

Wo und Wann?
Zuerst muss sicherlich die Frage gestellt werden, in welchen Szenarien Caching typischerweise sinnvoll ist und in welchen nicht? Caching von Daten ist immer dann sinnvoll, wenn Informationen mehrfach abgefragt werden und sich diese Informationen nicht kontinuierlich ändern, sie also eine längere Gültigkeitsdauer besitzen - wie beispielsweise Lookup- und Referenzdaten, etwa eine Liste mit Wochentagen oder Umrechnungskursen, die sich nur täglich ändern. Aber auch Stammdaten wie die Lieferanschrift eines Kunden, die im Laufe des Anwendungsflusses wiederkehrend dargestellt wird, bieten sich für ein Caching an. Im Umkehrschluss ist Caching nicht sinnvoll für Bewegungsdaten, die vom Benutzer aktualisiert werden, oder Daten, die immer den aktuellen Wert anzeigen sollen. Bewegungsdaten können zum Beispiel die Bestellinformationen in einem Warenkorb sein, mit dem der Benutzer arbeitet und bei dem er selbstverständlich immer sofort sehen möchte, wenn er die Anzahl der Einträge ändert. Auch Daten wie zum Beispiel Börsenkurse, die immer aktuell sein müssen, sollten nicht gecached werden.
Caching sollte immer so weit wie möglich entfernt von der Datenquelle erfolgen. Beim Betrachten einer typischen Anwendung mit einem Windows Forms Client, einer Schicht mit Geschäftslogik und einer angeschlossenen Datenbank liegt es nahe, die das Caching bereits auf dem Windows Forms Client zu implementieren. Durch dieses Nach-vorn-Ziehen des Caches zum User Interface werden sowohl die Netzwerklast als auch die Last auf Applikationsserver und Datenbank verringert. Allerdings wird damit nicht ausgeschlossen, dass auch auf Applikations- und Datenbankserver ein Caching stattfinden kann und soll.
Die Umsetzung in der Praxis
Das Design des EntLib Caching Application Block baut auf Standard-Pattern und bereits anderen Application Blocks (z.B. Configuration) auf. Über das Objekt CacheManagerFactory, das eine Factory für CacheManager-Objekte zur Verfügung stellt, erfolgt der Zugriff auf den eigentlichen Cache. Das Cache-Objekt implementiert die Caching-Funktionalität und stellt die Verbindung zu den Cache-Speichern (BackingStore) dar. Der Caching Application Block bietet standardmäßig die folgenden Cache-Speicher:
  • In Memory
  • Datenbank
  • Isolated Storage

Welcher Cache-Speicher verwendet wird, lässt sich über das Enterprise Library Configuration Tool in der XML-Konfigurationsdatei für die Anwendung einstellen. Beim Verwenden des In-Memory-Cache-Speichers werden die Daten nicht persistiert. Ist die Application Domain beendet, gehen auch die gecachten Daten verloren. Nicht so bei den beiden anderen Cache-Speichern: Wird eine Datenbank verwendet, zum Beispiel als Cache auf einem Applikationsserver, kann dieser Cache über Maschinengrenzen hinweg verwendet werden. Hierbei muss jedoch die Aktualisierung des Caches genau bedacht werden. Auch nach Beendigung der Anwendung stehen die Informationen weiter zur Verfügung. Der Cache-Speicher im Isolated Storage bietet sich vor allem dann an, wenn die Informationen persistent auf nur einer Maschine gehalten werden sollen. In allen Fällen befindet sich jedoch eine Kopie der gecachten Daten im Hauptspeicher und ist somit im schnellen Zugriff.
Der Anwendungsentwickler verwendet eine sehr einfache Schnittstelle des CacheManager, um auf die Daten im Cache zuzugreifen. In den Cache können Instanzen von eigenen Klassen, Value Types und Reference Types abgelegt werden. Einzige Voraussetzung: Sie müssen serialisierbar sein. Die Methoden des CacheManager pictureen die folgende Basisfunktionalität ab:
  • Hinzufügen von Items in den Cache
  • Lesen von Items aus dem Cache
  • Entfernen von Items aus dem Cache
  • Löschen aller Items aus dem Cache

Die Einfachheit der Programmierschnittstelle ist in dem Codebeispiel in Listing 1 zu erkennen. Es zeigt, wie eine Instanz einer eigenen Klasse aus dem Cache gelesen wird, und, falls noch nicht vorhanden, in den Cache geschrieben wird.

Listing 1
Ein Beispiel für ein implementiertes Caching
  1. private Category GetCategory(int searchId)
  2. {
  3. // Umwandeln der Kategory-ID in einen String
  4. string categoryId = Convert.ToString(searchId);
  5. // Erzeugen einer Instanz einer eigenen Klasse
  6. Category category = null;
  7. // Instanziieren des Cache Managers
  8. CacheManager categoriesCache = CacheFactory.GetCacheManager("Categories");
  9. // Laden der Instanz für die Kategorie aus dem Cache anhand der ID (Key)
  10. category.Name = categoriesCache.GetData(categoryId) as string;
  11. // Wenn die ID nicht gefunden wurde, dann ist das Item nicht im Cache
  12. if(category == null)
  13. {
  14. // Festlegen der Lebensdauer des Items
  15. AbsoluteTime absolutTime =
  16. new AbsoluteTime(new DateTime(2006, 01, 01, 0, 0, 0));
  17. // Laden des Items vom Web Service anhand der ID
  18. category = service.GetCategory(categoryId);
  19. // Schreiben des geladenen Category-Objektes in den Cache
  20. categoriesCache.Add(categoryId, category,
  21. CacheItemPriority.Normal, null, absolutTime);
  22. }
  23. }

Der in Listing 1 abgepictureete Cache stellt mithilfe des Background Scheduler fest, ob die Lebenszeit von Items innerhalb des Cache immer noch aktiv ist. Sollte die Lebenszeit abgelaufen sein, wird dieses Item aus dem Cache (im Hauptspeicher wie auch im Cache-Speicher) entfernt. Das Intervall, in dem dieser Expiration Task ausgeführt wird, ist ebenfalls konfigurierbar. Die Lebenszeit eines Items ist nach folgenden Kriterien einstellbar:
  • Absolute - Lebenszeit endet zu einem festgelegten, vorgegebenen Zeitpunkt.
  • Sliding - Lebenszeit endet nach einer bestimmten Zeit des Nicht-Zugreifens auf ein Item.
  • Extended Format - Nach bestimmten Regeln, z.B. einmal in der Woche, endet die Lebenszeit des Items.
  • File Dependency - Abhängig von der Änderung einer Datei endet die Lebenszeit des Items und es wird ungültig.

Neben dem Überprüfen der Lebenszeit von Items wird zusätzlich bei jedem Einfügen von neuen Items in den Cache überprüft, ob die maximale Anzahl von zugelassenen Items (einstellbar) im Cache überschritten ist. Sollte dies der Fall sein, wird anhand der Priorität eines jeden Items und des letzten Zugriffs auf das Item entschieden, ob es aus dem Cache entfernt wird (Scavenging). Folgende Prioritäten sind beim Hinzufügen eines Items einstellbar: Low, Normal, High und Not Removable. Somit wird erreicht, dass zuerst immer lange nicht genutzte Items mit einer niedrigen Priorität durch den Scavenging-Prozess entfernt werden. Wie bereits erwähnt, darf der Caching Application Block nicht losgelöst vom Rest der Enterprise Library betrachtet werden. Er kann zum Beispiel den Cryptography Application Block nutzen, um die im Cache-Speicher abgelegten Daten zu verschlüsseln. Dies ist für den Anwendungsentwickler vollkommen transparent - er muss hierfür keine Zeile Code schreiben. Die Verschlüsselung kann über die Konfiguration der Anwendung aktiviert werden. Dadurch ist es möglich, Verschlüsselung auch nachträglich einzuführen. Von der Enterprise Library werden alle symmetrischen Verschlüsselungsverfahren des .NET Framework unterstützt. Neben der Unterstützung für Verschlüsselung, die durch einen Cryptography Application Block erreicht wird, ist auch eine Einbindung in den Data Access Block vorhanden, der dann als Cache-Speicher zur Verfügung steht.
Erweiterbarkeit
Generell sind die Enterprise Library Application Blocks so aufgebaut, dass sie erweiterbar sind. Dies gilt selbstverständlich auch für den Caching Application Block. Das ist auf zwei Arten möglich: Zum einen durch das Hinzufügen von zusätzlichen Cache-Speichern. Hierfür muss ein Objekt entwickelt werden, welches vom BaseBackingStore abgeleitet ist. Zum anderen ist es möglich, das Verhalten und die Lebenszeit von Items im Cache zu beeinflussen. Hierfür müssen Komponenten entwickelt werden, die die ICacheItemExpiration-Schnittstelle implementieren. Damit kann ein eigenes Verhalten implementiert werden, nach dem die Lebenszeit von Objekten im Cache beurteilt wird. Die zweite Möglichkeit ist das Bereitstellen eines Objektes, welches die Schnittstelle ICacheRefreshAction implementiert. Damit ist der Cache in der Lage, ein Item automatisch zu aktualisieren, also mit neuen Originaldaten zu versorgen und die alten Daten im Cache zu verwerfen.
Fazit
Mit dem Caching Application Block wird es dem Entwickler wirklich sehr einfach gemacht, Standard-Caching-Mechanismen zu implementieren und in der eigenen Anwendung zu nutzen. Die Schnittstellen der Objekte sind extrem simpel gehalten und decken somit bereits etwa 90 Prozent der möglichen Anwendungsfälle ab. Die Erweiterbarkeit des Application Block ermöglicht eine noch höhere Abdeckung für eigene Bedürfnisse. Die interne Implementierung und die architektonische Umsetzung stellen sicher, dass der Caching Application Block performant und skalierbar ist. In jeder Situation werden die Caching-Daten im Memory gehalten und müssen nicht z.B. neu aus dem Datenspeicher gelesen werden. Damit kann dieser Block bedenkenlos auch unter hohen Anforderungen einer Enterprise-Anwendung eingesetzt werden. Wünschenswert für die zukünftige Weiterentwicklung des Caching Application Block wäre eine breitere Unterstützung des Item-Lebenszeit-Managements, nämlich so, dass das Management anhand einer Abhängigkeit der Originaldaten arbeitet. Die File-Dependency-Unterstützung zeigt bereits, in welche Richtung das gehen kann. Das Gleiche wäre für Daten in einer Datenbank auch denkbar. Wenn sich der entsprechende Datensatz ändert, müsste das Cache Item automatisch ungültig werden oder - noch besser - sich selbstständig aktualisieren. Einen kleinen Vorgeschmack liefert SQL Server 2005 im Zusammenspiel mit dem .NET Framework, da hier eine intrinsische Unterstützung für eine solche datenbankabhängige Cache Dependency zur Verfügung steht.

Enterprise Library
Im Rahmen der Artikelserie zur Enterprise Library sind im dot.net magazin bereits folgende Artikel erschienen:
  • Ausgabe 7/8.05: Sieben auf einen Streich - Die Microsoft Enterprise Library 1.0 im Überblick
  • Ausgabe 9.05 (online): Der Configuration Application Block im Detail
  • Ausgabe 11.05: Spurensicherung - Der Logging & Instrumentation Application Block im Detail
  • Ausgabe 12.05: Krisenstab - Der Exception Handling Application Block

Stefan Zill ist Architekt und Leiter der EAI-Gruppe bei Avanade und arbeitet im Bereich Solution Development - Sie erreichen ihn unter stefanz@avanade.com.
Links & Literatur


Anzeige

Kommentare

zurück zum Seitenanfang