Open Source Java-Projekte: Java Caching System

Steve Haines, Spezialist für Enterprise Java, erweitert diesen Monat die Open Source Java-Projektreihe mit einer Einführung in das Java Caching System (JCS), eine robuste Caching-Lösung auf Unternehmensebene. Steve beginnt mit einer kurzen Einführung in das Caching und erläutert die Kriterien für die Bestimmung, ob Objekte zwischengespeichert werden sollen und ob Ihre Anwendung von einem Cache profitieren würde. Anschließend zeigt er Ihnen, wie Sie JCS konfigurieren und damit eine Caching-Anwendung erstellen.

Das Java Caching System (JCS) ist ein robustes Open Source-Caching-Produkt, das über das Teilprojekt Apache Jakarta veröffentlicht wird. Es bietet die Standardfunktionen, die Sie von einem Cache-System erwarten würden, wie z. B. In-Memory-Caching und Algorithmen zum selektiven Entfernen von Objekten aus dem Cache. Es bietet auch erweiterte Funktionen wie indiziertes Festplatten-Caching und Unterstützung für verteilte Caches.

Ein JCS-Cache hat eine kartenartige Struktur, in der Daten als Name-Wert-Paar im Cache gespeichert werden. JCS unterteilt den Cache in Regionen . Jede Region hat ihre eigene Konfiguration sowie einen eigenen Satz von Name-Wert-Paaren. Jede Region kann:

  • Anders dimensioniert sein
  • Anders umgesetzt werden
  • Enthalten verschiedene Daten

Die Schlüssel (die Namen in den Name-Wert-Paaren) in einer Region können mit den Schlüsseln in anderen Regionen identisch sein. Dies ist wichtig, da Sie damit separate Caches für verschiedene Objekte in derselben JVM verwalten können - und alle in einer einzigen Eigenschaftendatei definiert sind.

Open Source Lizenzen

Jedes der in dieser Reihe behandelten Open Source-Java-Projekte unterliegt einer Lizenz, die Sie verstehen sollten, bevor Sie das Projekt in Ihre eigenen Projekte integrieren. JCS unterliegt der Apache-Lizenz. Weitere Informationen finden Sie unter Ressourcen.

In diesem Artikel wird JCS erläutert, indem zunächst gezeigt wird, wie Sie die aktuelle Version erhalten und installieren. Ich werde dann erklären, was ein Cache ist, warum Sie einen verwenden könnten und ob es die richtige Lösung für eine bestimmte Anwendung ist oder nicht. Als Nächstes werden Sie sich mit der JCS-Eigenschaftendatei befassen, die der beste Weg zum Verständnis von JCS ist. Schließlich erstellen Sie eine Beispiel-Caching-Anwendung, die JCS verwendet.

Beginnen Sie mit JCS

Sie können JCS von der Downloadseite der JCS-Projektsite herunterladen. Zum jetzigen Zeitpunkt ist die neueste Version 1.3. Laden Sie die Binärdistribution herunter (entweder als TAR-Datei auf Unix-Systemen oder als ZIP-Datei unter Windows) und dekomprimieren Sie sie in ein lokales Verzeichnis auf Ihrem Computer.

Das Stammverzeichnis des Installationsverzeichnisses enthält jcs-1.3.jar, das Sie Ihrem hinzufügen müssen, CLASSPATHbevor Sie eine JCS-Anwendung kompilieren und ausführen.

Klassendokumentation Goldmine

In diesem Artikel sowie in Ihren eigenen unabhängigen Studien werden Sie feststellen, dass das JCS- docsVerzeichnis eine unschätzbare Ressource für Informationen zu JCS ist, einschließlich der API-Dokumentation. Das robuste Javadoc-Dokument ist Ihre Autorität für das Verständnis der Verwendung von JCS-Klassen.

Sie benötigen zwei Abhängigkeiten:

  • Commons Logging
  • Concurrent

Fügen Sie in Commons Logging commons-logging.jarzu Ihrem hinzu CLASSPATH.

Eine schnelle Caching-Grundierung

Ein Cache dient zum Speichern von Objekten, normalerweise im Speicher, für den sofortigen Zugriff einer Anwendung. Eine Anwendung interagiert mit einem Cache anders als mit externen Speicherlösungen. In der Regel erhält eine Anwendung eine Verbindung zu einer Datenbank, führt eine Abfrage über ein Netzwerk aus und analysiert die zurückgegebenen Ergebnisse. Ein Cache verwaltet eine Sammlung leicht verfügbarer Objekte in einer robusten kartenähnlichen Struktur, für die kein Netzwerkaufruf erforderlich ist. Die Leistung von Java-Unternehmensanwendungen verbessert sich exponentiell, wenn nach dem Laden aus einer Datenbank auf wiederverwendbare Objekte in einem Cache zugegriffen wird, anstatt Remotedatenbankaufrufe durchzuführen.

Wenn Ihre Anwendung über eine überschaubare Anzahl von Objekten verfügt, auf die häufig zugegriffen wird, kann ein Cache wahrscheinlich seine Leistung verbessern. Java-Anwendungen werden durch die verfügbaren Ressourcen in der JVM eingeschränkt, von denen der wertvollste Speicher ist. Es macht keinen Sinn, einer JVM Speicher zu entziehen, um Objekte zu speichern, auf die selten zugegriffen wird. Es ist wahrscheinlich besser, ein Objekt zu laden, auf das bei Bedarf alle paar Stunden zugegriffen wird, und genügend freien Speicher für andere Ressourcen zu belassen. Auf der anderen Seite ist es besser, Objekte, auf die mehrmals pro Minute - oder sogar mehrmals pro Stunde - zugegriffen wird, in einen Cache zu laden und sie aus dem Speicher bereitzustellen, als jedes Mal, wenn das Objekt benötigt wird, einen Fernaufruf zu tätigen. Wenn die Anzahl der Objekte, auf die Ihre Anwendung häufig zugreift, im verfügbaren Speicher verwaltet werden kann,dann ist es ein guter Kandidat für das Caching. Aber wenn es zugreiftMillionen von Objekten häufig, dann ist es möglicherweise immer noch im besten Interesse einer Anwendung, Objekte nach Bedarf zu laden, anstatt 75 Prozent des Heaps einer JVM zum Hosten des Caches zu verwenden.

Caching versus Pooling

In Diskussionen über das Caching kommt es häufig zu Verwirrung über die Unterscheidung zwischen einem Cache und einem Pool. Welche Objekte sollten zwischengespeichert und welche Objekte gepoolt werden? Die Antwort liegt in der Natur der Objekte selbst. Wenn ein Objekt den Status beibehält, sollte es zwischengespeichert werden. Zustandslose Objekte sollten zusammengefasst werden. Betrachten Sie als Analogie zwei Aktivitäten: Lebensmittel in einem Supermarkt kaufen und ein Kind von der Schule abholen. Jeder Kassierer kann jeden Kunden im Supermarkt auschecken. Es spielt keine Rolle, welche Kassiererin Sie erhalten, daher sollten Kassierer zusammengefasst werden. Wenn Sie Ihr Kind von der Schule abholen, möchten Sie, dass Ihr Kind nicht das eines anderen ist, daher sollten Kinder zwischengespeichert werden.

Bei der Extrapolation dieser Idee auf Enterprise Java sollten Ressourcen wie Datenbankverbindungen und Business Processing Beans zusammengefasst werden, während Objekte wie Mitarbeiter, Dokumente und Widgets zwischengespeichert werden sollten. Es spielt keine Rolle, welche Datenbankverbindung Ihre Anwendung aus einem Verbindungspool erhält - alle tun dasselbe -, aber wenn Sie sich selbst eine Gehaltserhöhung geben möchten, ist es wichtig, dass Sie Ihr Mitarbeiterobjekt erhalten.

Grundlegendes zu JCS-Regionen

Die Verwendung von JCS ist eigentlich recht einfach, Sie benötigen jedoch grundlegende Kenntnisse darüber, wie JCS Cache-Regionen definiert und wie sie konfiguriert werden können. Die JCS-Eigenschaftendatei ist der logische Ort, um JCS zu verstehen. Listing 1 zeigt eine Beispiel-JCS-Eigenschaftendatei.

Listing 1. Eine JCS-Eigenschaftendatei (cache.ccf)

# DEFAULT CACHE REGION jcs.default=DC jcs.default.cacheattributes= org.apache.jcs.engine.CompositeCacheAttributes jcs.default.cacheattributes.MaxObjects=1000 jcs.default.cacheattributes.MemoryCacheName= org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.default.cacheattributes.UseMemoryShrinker=true jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.default.cacheattributes.ShrinkerIntervalSeconds=60 jcs.default.elementattributes=org.apache.jcs.engine.ElementAttributes jcs.default.elementattributes.IsEternal=false jcs.default.elementattributes.MaxLifeSeconds=21600 jcs.default.elementattributes.IdleTime=1800 jcs.default.elementattributes.IsSpool=true jcs.default.elementattributes.IsRemote=true jcs.default.elementattributes.IsLateral=true # PREDEFINED CACHE REGIONS jcs.region.musicCache=DC jcs.region.musicCache.cacheattributes= org.apache.jcs.engine.CompositeCacheAttributes jcs.region.musicCache.cacheattributes.MaxObjects=1000 jcs.region.musicCache.cacheattributes.MemoryCacheName= org.apache.jcs.engine.memory.lru.LRUMemoryCache jcs.region.musicCache.cacheattributes.UseMemoryShrinker=true jcs.region.musicCache.cacheattributes.MaxMemoryIdleTimeSeconds=3600 jcs.region.musicCache.cacheattributes.ShrinkerIntervalSeconds=60 jcs.region.musicCache.cacheattributes.MaxSpoolPerRun=500 jcs.region.musicCache.elementattributes= org.apache.jcs.engine.ElementAttributes jcs.region.musicCache.elementattributes.IsEternal=false # AVAILABLE AUXILIARY CACHES jcs.auxiliary.DC= org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory jcs.auxiliary.DC.attributes= org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes jcs.auxiliary.DC.attributes.DiskPath=c:/temp jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000000 jcs.auxiliary.DC.attributes.MaxKeySize=1000000 jcs.auxiliary.DC.attributes.MaxRecycleBinSize=5000 jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=300000 jcs.auxiliary.DC.attributes.ShutdownSpoolTimeLimit=60

Listing 1 enthält drei Abschnitte:

  • Die Standardregion definiert die Standardkonfiguration für alle Regionen, sofern sie nicht explizit von einer der anderen Regionen überschrieben wird.
  • Als nächstes folgt eine Liste vordefinierter (dh benutzerdefinierter) Cache-Regionen, die in diesem Fall die musicCacheim nächsten Beispiel verwendeten enthalten.
  • Hilfs-Caches definieren Hilfs- Caches, die in einen Cache-Bereich eingesteckt werden können. Obwohl jeder Cache-Bereich einen (und nur einen) Speicher-Auxiliar haben muss, kann er eine beliebige Anzahl anderer Auxiliaren haben, die zwischengespeicherte Daten enthalten können. In diesem Beispiel erstelle ich einen indizierten Festplatten-Cache, aber Sie können auch laterale und entfernte Hilfsprogramme definieren. Ein lateraler Auxiliary kann Ihre zwischengespeicherten Daten über einen TCP-Socket oder einen JGroups-Protokollstapel in andere Caches replizieren. Ein Remote-Auxiliary kann Daten über Remote Method Invocation (RMI) in andere Caches replizieren.

Jede Region kann sowohl Cache-Attribute als auch Elementattribute definieren . Ein Cache-Attribut definiert eine Konfigurationsoption für den Cache, während ein Elementattribut eine Konfigurationsoption für die Elemente im Cache definiert. Hier ist eine Zusammenfassung der Cache-Attributoptionen:

  • MaxObjects: Dies ist die maximal zulässige Anzahl von Objekten im Speicher.
  • MemoryCacheName: Mit dieser Eigenschaft können Sie den Speichermanager definieren, der als Ihr verwendet werden soll MemoryCache. Der Standardspeichermanager implementiert eine LRU-Strategie.
  • UseMemoryShrinker: Mit dieser Option kann JCS regelmäßig über den Cache iterieren und nach Objekten suchen, die entfernt werden können (Elemente, die abgelaufen sind oder ihre maximale Leerlaufzeit überschritten haben). Der Standardwert ist false.
  • MaxMemoryIdleTimeSeconds: Wenn der Speicher-Shrinker aktiviert ist, teilt diese Eigenschaft JCS mit, wie lange ein Objekt inaktiv bleiben kann, bevor der Shrinker es entfernt (und spult es auf die Festplatte, wenn ein indizierter Festplatten-Cache erstellt wurde). Der Standardwert ist -1, wodurch diese Option deaktiviert wird.
  • ShrinkerIntervalSeconds: Wenn der Speicher-Shrinker aktiviert ist, teilt diese Eigenschaft JCS mit, wie oft der Shrinker ausgeführt werden soll. Der Standardwert ist 60 Sekunden.
  • DiskUsagePattern: Wenn ein Festplattencache aktiviert ist, teilt diese Eigenschaft JCS mit, wie Daten beibehalten werden sollen, wenn der Speichercache voll ist. Der Standardwert ist SWAP, dass Elemente nur dann auf die Festplatte gespoolt werden, wenn der Speichercache voll ist. Die andere Option ist UPDATE, dass alle Daten auf der Festplatte gespeichert bleiben, jedoch nur, wenn die Daten aktualisiert werden. Wenn ein JDBC-Auxiliary als Festplatten-Cache definiert wurde, verbleiben alle Objekte im Speicher (bis der Speicher voll ist) und werden auch in einer Datenbank gespeichert, was eine gute Leistung und Zuverlässigkeit bietet.

Und hier sind die Elementattributoptionen:

  • IsEternal: Wenn ein Element ewig ist, kann es nicht aus dem Cache entfernt werden, da es seine maximale Lebensdauer überschreitet. Diese Option ist standardmäßig aktiviert true.
  • MaxLifeSeconds: If elements are not eternal, this option defines the maximum life of each object before it is removed. If the memory shrinker is running, objects are removed by the shrinker; if not, they are removed when they're accessed. This option defaults to -1, which disables the option.
  • IsSpool: This option defines whether or not an element can be spooled out to disk. It defaults to true.
  • IsLateral: This option defines whether or not an element can be sent to a lateral cache. It defaults to true.
  • IsRemote: This option defines whether or not an element can be sent to a remote cache. Defaults to true.

In Listing 1, I created a region named musicCache that holds up to 1,000 items in memory. Its memory manager uses a LRU algorithm: when the cache is full and JCS needs to make room for new items, it will remove items that have not been recently accessed. It has the memory shrinker enabled, and the shrinker will run every 60 seconds. It will evict items that sit idle for more than 60 minutes (3,600 seconds.) Its items are not eternal, and they can be written out to disk, to a lateral cache, or to a remote cache.

Note that the IsSpool, IsLateral, and IsRemote settings are inherited from the default settings. Because the jcs.region.musicCache element is set to DC, it is defined not only to maintain an in-memory cache, but also to use the indexed disk cache as an auxiliary. (The property can be set to a comma-separated list of multiple auxiliaries.) The disk cache is configured to store items in the c:/temp directory. (JCS prefers forward slashes to backslashes.) The remaining attributes configure the disk cache using an IndexedDiskCacheAttribute object; you can read about these attributes in the JCS Javadoc.

Building a sample caching application

Once you understand how to configure JCS, building a caching application is straightforward. The application needs to be able to:

  • Initialize the cache from its configuration file
  • Access a region in the cache
  • Laden Sie Objekte in den Cache
  • Objekte aus dem Cache abrufen
  • Entfernen Sie Objekte aus dem Cache

Der Cache kann entweder automatisch oder manuell initialisiert werden. Wenn Sie Ihre Konfigurationsdatei benennen cache.ccfund direkt in Ihrem CLASSPATH(z. B. Ihrem Root-Build-Verzeichnis) ablegen, findet JCS beim ersten Aufruf die Datei und initialisiert sie entsprechend. Wenn Sie Ihre Konfigurationsdatei an einer anderen Stelle speichern oder anders benennen müssen, können Sie die org.apache.jcs.utils.props.PropertyLoader's loadProperties()Methode verwenden, um JCS-Eigenschaften aus einer beliebigen Eigenschaftendatei zu laden.