Freitag, 14. August 2015

Second Level Cache

Wieder mal ein technischer Post:
Ich habe Hibernate, infinispan und jboss kombiniert. Zusätzlich mich noch mit der CLI rumgeschlagen.
Was ist der Anlass: Wir haben in unserem Server einige (6) Tabellen, die nur gelesen werden. Die Inhalte der Tabellen werden im Moment über einen Threadlokalen Cache geliefert. Die Implementierung ist überflüssig, weil dieselbe Funktionalität über ein paar Annotationen und Konfigurationen zu realisieren ist.
Heute habe ich Konfigurationen hergestellt, mit denen die beschriebenen selbst hergestellten Caches, die minütlich invalidiert werden, bei dem Wiederauffüllen aus dem Second Level Cache von Hibernate beliefert werden.

An den Entitäten und den Queries:

Annotieren mit @Cacheable.

Die zu cachenden Queries bekommen:

hints = {@QueryHint(name = "org.hibernate.cacheable", value = "true")}

Ohne diese Queries zu cachen würden nur  Zugriffe über die Primärschlüssel vom 2nd Level Cache bedient werden. Für die betroffenen Queries wird pro Parameter-Kombination im Cache hinterlegt, was das Ergebnis ist.

persistence.xml

Für JPA wir das Cachen aktiviert mit: 

<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

damit wird bewirkt, dass nur die entsprechend annotierten Entitäten gecacht werden. Für Hibernate ist es auch noch notwenig das cachen einzuschalten. Aus diesem Grund wird zu der sicher schon vorhanden Property-Liste noch:

<property name="hibernate.cache.use_structured_entries" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>


 hinzugefügt. Allerdings wird es jetzt aber noch notwendig für Hibernate eine sog. RegionFactory bereitzustellen. Für JBoss wurde hier: 

<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.infinispan.JndiInfinispanRegionFactory" />
<property name="hibernate.cache.infinispan.cachemanager" value="java:jboss/infinispan/mss" />

notwendig. Im JBoss ist schon ein cache mit Namen hibernate vorkonfiguriert. Wenn man diesen verwenden möchte sind die beiden Zeilen nicht notwendig.
Für den beschriebenen Anwendungsfall ist es allerdings sinnvoll, einen reinen lokalen Cache zu definieren. Aus diesem Grund wurde ein spezieller Infinispan-Cache eingerichtet: 

<cache-container name="mss" default-cache="local-query" jndi-name="java:jboss/infinispan/mss" start="EAGER" module="org.jboss.as.jpa.hibernate:4">
    <local-cache name="entity">
        <transaction mode="NON_XA"/>
        <eviction strategy="LRU" max-entries="10000"/>
        <expiration lifespan="1800000"/>
    </local-cache>
    <local-cache name="local-query">
        <transaction mode="NONE"/>
        <eviction strategy="LRU" max-entries="10000"/>
        <expiration max-idle="1000000"/>
    </local-cache>
    <local-cache name="timestamps">
        <transaction mode="NONE"/>
        <eviction strategy="NONE"/>
    </local-cache>
</cache-container>

Das kann mit der CLI in folgender Weise eingerichtet werden:
# $JBOSS_HOME/bin/jboss-cli.sh --file=/path/to/this/file.

if (outcome == success) of /subsystem=infinispan/cache-container=mss
   /subsystem=infinispan/cache-container=mss:remove()
end-if

/subsystem=infinispan/cache-container=mss:add()
/subsystem=infinispan/cache-container=mss:write-attribute(name=default-cache,value=local-cache)
/subsystem=infinispan/cache-container=mss:write-attribute(name=start,value=EAGER)
/subsystem=infinispan/cache-container=mss:write-attribute(name=jndi-name,value=java:jboss/infinispan/mss)
/subsystem=infinispan/cache-container=mss:write-attribute(name=module,value=org.jboss.as.jpa.hibernate:4)
/subsystem=infinispan/cache-container=mss/local-cache=entity:add()
/subsystem=infinispan/cache-container=mss/local-cache=entity/transaction=TRANSACTION:add(mode=NON_XA)
/subsystem=infinispan/cache-container=mss/local-cache=entity/eviction=EVICTION:add(strategy=LRU,max-entries=10000)
/subsystem=infinispan/cache-container=mss/local-cache=entity/expiration=EXPIRATION:add(lifespan=1800000)
/subsystem=infinispan/cache-container=mss/local-cache=local-query:add()
/subsystem=infinispan/cache-container=mss/local-cache=local-query/transaction=TRANSACTION:add(mode=NONE)
/subsystem=infinispan/cache-container=mss/local-cache=local-query/eviction=EVICTION:add(strategy=LRU,max-entries=10000)
/subsystem=infinispan/cache-container=mss/local-cache=local-query/expiration=EXPIRATION:add(lifespan=1000000)
/subsystem=infinispan/cache-container=mss/local-cache=timestamps:add()
/subsystem=infinispan/cache-container=mss/local-cache=timestamps/transaction=TRANSACTION:add(mode=NONE)
/subsystem=infinispan/cache-container=mss/local-cache=timestamps/eviction=EVICTION:add(strategy=NONE)

Danach erscheint pro zu cachende Entität unter JMX ein cache bei dem auch Statistiken abzufragen sind.   


Keine Kommentare:

Kommentar veröffentlichen