Skip to content

Asynchrones Laden in Guava Cache

Google Guava Cache ist eine weitverbreitete Komponente zur Implementierung von caches. Sie bietet ein Framework um schnell in-memory caches zu implementieren. Unter anderem erlaubt ein CacheLoader den asynchronen refresh von Einträgen. Dabei muss man aber beachten, dass dies nicht out-of-the-box geschieht, sondern dass man dazu eine eigene Logik implementieren muss die das refreshen/laden im Hintergrund implementiert.

Die Grundlagen sind im Guava Wiki beschreiben, ich hab aber aktuell ein Issue offen in dem ich die Dokumentation einer bestehenden Hilfsmethode vorschlage:

Ein kleiner Wrapper wird von Google seit Guava 17 bereitgestellt, man kann damit einen synchronen CacheLoader der keine besondere async-logik enthält wrappen, so dass die refreshes an einen Executor delegiert werden: CacheLoader.asyncRefresh().

Damit lässt sich schnell aus einem vorhandenen CacheLoader ein asynchroner machen. Dabei ist zu beachten dass der Wrapper zusätzliche Objekte erstellt bei jedem re-fresh. Wenn es also auf leichtgewichtige Implementierung ankommt, und wenn eventuell ein Teil des Refresh codes synchron laufen kann, so ist es besser die Logik selbst zu implementieren (man muss nur darauf achten die Erstellung der Future erfolgt synchron, alles was bis zur completion ausgeführt wird läuft im Hintergrund und verzögert keine Lookups).

Folgende Eigenheiten hat das Refreshing:

  • Wenn das Refreshing mittels cache.refresh("key") angestoßen wird, so wartet der refresh Aufruf bis der CacheLoader fertig ist (genauer gesagt, bis die reload future zurückgegeben wurde). Das blockiert nur den Aufrufer-thread, alle anderen Threads die in der Zwischenzeit Cache lookups (für den gleichen Key) machen, bekommen den noch gecachten (alten) Wert.
  • Wenn ein Cache invalidiert wird oder ein Wert aus dem Cache expired, so gibt es keinen alten bestehenden Wert und jeder folgende lookup wird auf das Ende des CacheLoader.load warten müssen. Dabei wird der load pro Key nur einmal gestartet und alle anderen Threads die in dem Zeitraum den Wert anfordern werden angehalten - das ist gut da es die Parallelität des CacheLoader anfragen limitiert. Diese Methode wird nicht in einer asynchronen Variante gewrapped.
  • Wenn refreshing nicht wegen einem direkten refresh(key) Aufruf notwendig wird sondern durch ablaufen des refreshAfterWrite() Zeitraums, so wird das Refreshing durch den nächsten lookup angestoßen. Wenn der CacheLoader synchron ist wird dies auch den (zufällig nächsten) lookup Thread so lange blockieren. Alle weiteren Lookups werden nicht blockiert sondern bekommen den alten Wert. D.h. man muss hier mit regelmäßigen einzelnen verzögerten Lookups rechnen und man kann nicht davon ausgehen dass die Anfragereihenfolge klar in "alte Werte - neue Werte" sortiert werden kann.

Trackbacks

Keine Trackbacks

Kommentare

Ansicht der Kommentare: Linear | Verschachtelt

Noch keine Kommentare

Kommentar schreiben

BBCode-Formatierung erlaubt
Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Die angegebene E-Mail-Adresse wird nicht dargestellt, sondern nur für eventuelle Benachrichtigungen verwendet.
Um einen Kommentar hinterlassen zu können, erhalten Sie nach dem Kommentieren eine E-Mail mit Aktivierungslink an ihre angegebene Adresse.

Um maschinelle und automatische Übertragung von Spamkommentaren zu verhindern, bitte die Zeichenfolge im dargestellten Bild in der Eingabemaske eintragen. Nur wenn die Zeichenfolge richtig eingegeben wurde, kann der Kommentar angenommen werden. Bitte beachten Sie, dass Ihr Browser Cookies unterstützen muss, um dieses Verfahren anzuwenden.
CAPTCHA