In Teil 1 dieser Artikelserie haben wir gesehen, welche fortgeschrittenen Funktionen das Ehcache-API anbietet. Im Fokus des zweiten Teils steht BigMemory [1]. Damit lassen sich unter anderem Garbage-Collection-(GC-)Probleme lösen. Erklärt wird außerdem, was In-Memory Data Management bedeutet, was ein Distributed System ist und wie eine moderne In-Memory-Architektur aussieht.
BigMemory ist einerseits eine Software, andererseits eine Lösung, um Big Data „in Memory“ zu halten. Es vergrößert den Speicherbereich einer Java-Anwendung so, dass zusätzlich ein Off-Heap-Bereich zur Verfügung steht. Dazu verwendet man intern direkte java.nio.ByteBuffers, um die Daten zu speichern. ByteBuffers sind sehr nützlich, da die Daten direkt im Off-Heap-Bereich der JVM gespeichert werden können und es hier weder Speicherbegrenzung (wie bei 32-Bit-JVM) noch GC-Probleme gibt (Abb. 1). Man kann zum Beispiel mit ByteBuffers Daten mit einer C-Anwendung austauschen, weil Letztere problemlos auf den Off-Heap-Speicherbereich der JVM zugreifen kann und umgekehrt. BigMemory muss zwar die Daten (de)serialisieren, nutzt dafür aber seine eigene, optimierte Methodik.
Teil 1: Ehcache Advanced
Teil 2: BigMemory und Distributed In-Memory Data Management
Da GC im Off-Heap kein Objekt kontrollieren kann, werden die hier gehaltenen Daten nie unter GC-(StopTheWorld-)Pausen leiden. Das beeinflusst maßgeblich die Geschwindigkeit der Anwendung, die einen Off-Heap-Bereich nutzt. Die maximale Größe des Hauptspeichers liegt aktuell bei zwei Terabyte, die mithilfe von BigMemory großteils (On-Heap und Betriebssystem braucht auch Speicher) für die Anwendung zur Verfügung stehen. Diese Daten liegen immer noch im Hauptspeicher. Somit sind sie für die Anwendung sehr schnell erreichbar (mehrere hundert Gigabyte Daten unter 100 Mikrosekunden). Dank des Off-Heaps hat BigMemory eine sehr niedrige Latenzzeit, kann einen sehr hohen Datendurchsatz (über 200 000 Transaktionen/Sekunde mit 100 GB Daten [2]) erreichen, und die Geschwindigkeit des Datentransfers ist vorhersehbar. Das ist vor allem dann von Bedeutung, wenn die Daten innerhalb einer vordefinierten Zeit im Rahmen eines Service Level Arguments (SLA) zur Verfügung stehen sollen. Mit normalem On-Heap-Speicher ist es nicht möglich, da die GC-Pausen schlecht prognostizierbar sind.
Wir sehen also, dass BigMemory keine spezielle Hardware benötigt (also keine Appliance-Lösung) und für alle Java-Anwendungen einfach verwendbar ist.
BigMemory nutzt das Ehcache-API. Hier kann die bestehende Ehcache-Konfiguration einfach mit BigMemory erweitert werden:
<cache name="BigMemoryCache"
...
maxBytesLocalOffHeap="16G"
overflowToOffHeap="true">
...
Die Option maxBytesLocalOffHeap aktiviert BigMemory und gibt gleichzeitig die Größe des Off-Heap-Bereichs an. Der Parameter overflowToOffHeap="true" ist sehr empfehlenswert. Damit können die gecachten Objekte aus dem On-Heap-Cache (Ehcache) in den Off-Heap-Cache (BigMemory) wandern, wenn der On-Heap-Cache voll ist.
Um den Off-Heap-Bereich zu konfigurieren, muss man den Parameter -XX:MaxDirectMemorySize beim Starten der JVM setzen. Dieser stellt den Gesamtspeicher der JVM ein, der aus On-Heap (-Xmx) und Off-Heap (MaxDirectMemorySize – Xmx = Off-Heap) besteht. Der Wert darf natürlich nicht größer sein als die physische Speichergröße. Bei dieser Einstellung sollte man den Speicherbedarf des Betriebssystems unbedingt berücksichtigen (ein OS braucht ca. 1 GB). BigMemory bietet zwei verschiedene Versionen an:
BigMemory GO ist auf eine JVM begrenzt und eignet sich somit für Standalone-Szenarien (ein Applikationsserver ohne Distribution)
BigMemory MAX kann auf mehreren JVMs installiert werden, und so kann ein Terracotta Server Array (Distributed System) erstellt und aus verschiedenen Clients (mehreren Applikationsservern) verwendet werden
Beide Versionen haben eine kostenlose und eine lizenzpflichtige Variante. Einen detaillierten Vergleich der Features findet man unter [1].
In-Memory Data Management bedeutet eine mehrschichtige Architektur, in der die Daten „gemanagt“ im Speicher gehalten werden. Wie Abbildung 2 zeigt, ist BigMemory auch mehrschichtig aufgebaut. In der Fachsprache spricht man von Cache-Layers. Sie sind die wichtigsten Elemente einer In-Memory-Architektur. Der normale On-Heap-Speicherbereich (Layer 1 Heap) steht immer und für jede Java-Anwendung zur Verfügung. BigMemorys Off-Heap-Speicher, der in der JVM der Applikation ist, nennt man Layer 1 Off-Heap. Wenn wir mehr Speicher als unseren physischen Speicher benötigen, brauchen wir ein verteiltes System (Distributed System), in dem mehrere Cacheserver (Stripes) miteinander verbunden sind. Das nennen wir Layer 2 Cache oder Terracotta Server Array (kurz TSA). Wenn wir kein TSA haben (weil wir z. B. nur BigMemory GO benutzen), können wir einen DiskStore zusätzlich verwenden, um die Größe des Gesamtcaches zu erweitern. Es ist aber ratsam, bei größeren Datenmengen einen TSA zu verwenden. Ein weiterer wichtiger Teil des In-Memory Data Managements ist die Kontrolle der Daten. Die Daten in verschiedenen Cache-Layer zu speichern, ist nur dann sinnvoll, wenn ggf. beeinflusst werden kann, wann, wo und was gespeichert wird. BigMemory nutzt dafür den Automatic Resource Control (ARC). ARC ist ein Teil von Ehcache, da wir selbst bei Ehcache ein – zwar kleineres – In-Memory Data Management haben. In Teil 1 haben wir gesehen, wie ARC in Ehcache funktioniert. Jetzt ist BigMemory an der Reihe.
Unabhängig davon, welche Version man nutzt, wird ein Lizenz-Key benötigt. Bei BigMemory GO bekommt man ihn nach dem Download automatisch per E-Mail zugeschickt. Den Pfad, in dem sich die Lizenz-Key-Datei befindet, muss man beim JVM-Start mit dem Parameter wie folgt angeben:
-Dcom.tc.productkey.path=/path/to/terracotta-license.key
Nachdem wir den Lizenz-Key angegeben haben und die ehcache.xml (siehe Teil 1) mit dem Off-Heap-Bereich...