Bevezetés a koffeinbe

1. Bemutatkozás

Ebben a cikkben megnézzük a koffeint - a nagy teljesítményű gyorsítótár-könyvtár Java számára.

Egy alapvető különbség a gyorsítótár és az a között Térkép az, hogy a gyorsítótár kiüríti a tárolt elemeket.

An a kilakoltatási politika dönti el, mely objektumokat kell törölni bármikor. Ez a politika közvetlenül befolyásolja a gyorsítótár találati arányát - a könyvtárak gyorsítótárazásának alapvető jellemzője.

A koffein a Ablak TinyLfu kilakoltatási politika, amely a közel az optimális találati arány.

2. Függőség

Hozzá kell adnunk a koffein függőség a mi pom.xml:

 com.github.ben-manes.caffeine koffein 2.5.5 

Megtalálja a legújabb verzióját koffein a Maven Central-on.

3. A gyorsítótár feltöltése

Koncentráljunk a koffeinre három stratégia a gyorsítótár-populációhoz: kézi, szinkron és aszinkron betöltés.

Először írjunk egy osztályt azoknak az értéktípusoknak, amelyeket a gyorsítótárunkban tárolunk:

osztály DataObject {private final String adatok; privát statikus int objectCounter = 0; // standard konstruktorok / getterek nyilvános statikus DataObject get (String adatok) {objectCounter ++; return new DataObject (adatok); }}

3.1. Kézi kitöltés

Ebben a stratégiában manuálisan helyezünk értékeket a gyorsítótárba, és később visszakeresjük őket.

Inicializáljuk a gyorsítótárunkat:

Gyorsítótár gyorsítótár = Caffeine.newBuilder () .expireAfterWrite (1, TimeUnit.MINUTES) .maximumSize (100) .build ();

Most, némi értéket kaphatunk a gyorsítótárból a getIfPresent módszer. Ez a módszer visszatér nulla ha az érték nincs a gyorsítótárban:

Karakterlánc = "A"; DataObject dataObject = cache.getIfPresent (kulcs); assertNull (dataObject);

Tudunk töltse fel a gyorsítótárat manuálisan a tedd módszer:

cache.put (kulcs, dataObject); dataObject = cache.getIfPresent (kulcs); assertNotNull (dataObject);

Az értéket a kap módszer, amely a Funkció érvként egy kulccsal együtt. Ezt a függvényt a tartalékérték megadására fogják használni, ha a kulcs nincs a gyorsítótárban, amelyet a számítás után be kell illeszteni a gyorsítótárba:

dataObject = cache .get (kulcs, k -> DataObject.get ("Adatok A-hoz")); assertNotNull (dataObject); assertEquals ("Adatok A-hoz", dataObject.getData ());

A kap módszer a számítást atomszerűen végzi. Ez azt jelenti, hogy a számítás csak egyszer fog elvégezni - még akkor is, ha több szál egyszerre kéri az értéket. Ezért felhasználásával kap előnyösebb, mint getIfPresent.

Néha szükségünk van rá érvénytelenít néhány gyorsítótárazott értéket manuálisan:

cache.invalidate (kulcs); dataObject = cache.getIfPresent (kulcs); assertNull (dataObject);

3.2. Szinkron töltés

A gyorsítótár betöltésének ez a módszere a Funkció, amelyet az értékek inicializálására használunk, hasonlóan a kap a kézi stratégia módszere. Lássuk, hogyan tudjuk ezt felhasználni.

Először is inicializálnunk kell a gyorsítótárat:

LoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .expireAfterWrite (1, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));

Most lekérhetjük az értékeket a kap módszer:

DataObject dataObject = cache.get (kulcs); assertNotNull (dataObject); assertEquals ("Data for" + kulcs, dataObject.getData ());

A. Használatával értékkészletet is kaphatunk getAll módszer:

Map dataObjectMap = cache.getAll (Arrays.asList ("A", "B", "C")); assertEquals (3, dataObjectMap.size ());

Az értékeket az alapul szolgáló háttér-inicializálásból kapjuk le Funkció hogy átadták a épít módszer. Ez lehetővé teszi a gyorsítótár használatát fő homlokzatként az értékek eléréséhez.

3.3. Aszinkron töltés

Ez a stratégia ugyanúgy működik, mint az előző, de aszinkron módon hajtja végre a műveleteket, és visszaadja a CompletableFuture a tényleges érték birtokában:

AsyncLoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .expireAfterWrite (1, TimeUnit.MINUTES) .buildAsync (k -> DataObject.get ("Adatok" + k));

Tudunk használja a kap és getAll mód, ugyanúgy, figyelembe véve azt a tényt, hogy visszatérnek CompletableFuture:

Karakterlánc = "A"; cache.get (kulcs) .theAccept (dataObject -> {assertNotNull (dataObject); assertEquals ("Data for" + kulcs, dataObject.getData ());}); cache.getAll (Arrays.asList ("A", "B", "C")) .thenAccept (dataObjectMap -> assertEquals (3, dataObjectMap.size ()));

CompletableFuture gazdag és hasznos API-val rendelkezik, amelyről ebben a cikkben olvashat bővebben.

4. Értékek kilakoltatása

A koffeinnek van három stratégia az érték kilakoltatásához: méretalapú, időalapú és referencia-alapú.

4.1. Méretalapú kilakoltatás

Ez a típusú kilakoltatás azt feltételezi kilakoltatás történik, ha túllépik a gyorsítótár beállított méretkorlátját. Vannak a méret megadásának két módja - a gyorsítótárban lévő tárgyak számlálása vagy súlyuk megszerzése.

Lássuk, hogyan tudnánk számoljon objektumokat a gyorsítótárban. A gyorsítótár inicializálásakor a mérete egyenlő nulla:

LoadingCache cache = Caffeine.newBuilder () .maximumSize (1) .build (k -> DataObject.get ("Adatok" + k)); assertEquals (0, cache.estimatedSize ());

Érték hozzáadásakor a méret nyilvánvalóan megnő:

cache.get ("A"); assertEquals (1, cache.estimatedSize ());

Hozzáadhatjuk a második értéket a gyorsítótárhoz, ami az első érték eltávolításához vezet:

cache.get ("B"); cache.cleanUp (); assertEquals (1, cache.estimatedSize ());

Érdemes megemlíteni, hogy mi hívja a cleanUp módszer, mielőtt megkapja a gyorsítótár méretét. Ennek oka, hogy a gyorsítótár kiürítését aszinkron módon hajtják végre, és ez a módszer segít megvárni a kilakoltatás befejezését.

Azt is megtehetjük át egy mérlegelőFunkcióa gyorsítótár méretének megszerzéséhez:

LoadingCache cache = Caffeine.newBuilder () .maximumWeight (10) .weigher ((k, v) -> 5) .build (k -> DataObject.get ("Adatok" + k)); assertEquals (0, cache.estimatedSize ()); cache.get ("A"); assertEquals (1, cache.estimatedSize ()); cache.get ("B"); assertEquals (2, cache.estimatedSize ());

Az értékek eltávolításra kerülnek a gyorsítótárból, ha a súly meghaladja a 10-et:

cache.get ("C"); cache.cleanUp (); assertEquals (2, cache.estimatedSize ());

4.2. Időalapú kilakoltatás

Ez a kilakoltatási stratégia az a bejegyzés lejárati ideje alapján és három típusa van:

  • A hozzáférés után lejár - a bejegyzés az utolsó olvasás vagy írás bekövetkezte óta eltelt idő leteltével lejár
  • Írás után lejár - a bejegyzés az utolsó írás bekövetkezte óta eltelt idő elteltével lejár
  • Egyéni házirend - a lejárati időt minden egyes bejegyzéshez külön számítja ki a Lejárat végrehajtás

Konfiguráljuk az expire-after-access stratégiát a expireAfterAccess módszer:

LoadingCache cache = Caffeine.newBuilder () .expireAfterAccess (5, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));

Az expire-after-write stratégia konfigurálásához a expireAfterWrite módszer:

gyorsítótár = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .weakKeys () .weakValues ​​() .build (k -> DataObject.get ("Data for + k));

Egyéni házirend inicializálásához végre kell hajtanunk a Lejárat felület:

cache = Caffeine.newBuilder (). expireAfter (new Expiry () {@Orride public long expireAfterCreate (String kulcs, DataObject érték, hosszú currentTime) {return value.getData (). length () * 1000;} @Override public long expireAfterUpdate (Karaktersorozatkulcs, DataObject érték, hosszú currentTime, hosszú currentDuration) {return currentDuration;} @Orride public long expireAfterRead (Stringkulcs, DataObject érték, long currentTime, long currentDuration) {return currentDuration;}}. .get ("Adatok a" + k számára ");

4.3. Referencia alapú kilakoltatás

Konfigurálhatjuk a gyorsítótárunkat az engedélyezéshez a gyorsítótár kulcsainak és / vagy értékeinek szemétgyűjtése. Ehhez konfigurálnánk a WeakRefence kulcsokhoz és értékekhez egyaránt, és konfigurálhatjuk a SoftReference csak értékek szemétgyűjtésére.

A WeakRefence A használat lehetővé teszi az objektumok szemétgyűjtését, ha nincsenek erős utalások az objektumra. SoftReference lehetővé teszi az objektumok szemétszedését a JVM globálisan legkevésbé használt stratégiája alapján. További részletek a Java-hivatkozásokról itt találhatók.

Használnunk kellene Caffeine.weakKeys (), Caffeine.weakValues ​​(), és Caffeine.softValues ​​() az egyes lehetőségek engedélyezéséhez:

LoadingCache cache = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .weakKeys () .weakValues ​​() .build (k -> DataObject.get ("Adatok" + k)); cache = Caffeine.newBuilder () .expireAfterWrite (10, TimeUnit.SECONDS) .softValues ​​() .build (k -> DataObject.get ("Adatok" + k));

5. Frissítő

A gyorsítótár úgy konfigurálható, hogy a bejegyzések meghatározott idő után automatikusan frissüljenek. Nézzük meg, hogyan lehet ezt megtenni a refreshAfterWrite módszer:

Caffeine.newBuilder () .refreshAfterWrite (1, TimeUnit.MINUTES) .build (k -> DataObject.get ("Adatok" + k));

Itt meg kell értenünk a a különbség köztük lejárt utána és refreshAfter. Amikor a lejárt bejegyzést kéri, egy végrehajtás blokkol, amíg az új értéket a build nem számította volna ki Funkció.

De ha a bejegyzés frissíthető, akkor a gyorsítótár régi értéket ad vissza aszinkron módon töltse be újra az értéket.

6. Statisztika

A koffeinnek van eszköze statisztikák rögzítése a gyorsítótár használatáról:

LoadingCache cache = Caffeine.newBuilder () .maximumSize (100) .recordStats () .build (k -> DataObject.get ("Adatok a + k számára)"; cache.get ("A"); cache.get ("A"); assertEquals (1, cache.stats (). hitCount ()); assertEquals (1, cache.stats (). missCount ());

Mi is átmehetünk recordStats szállító, amely létrehozza a StatsCounter. Ez az objektum minden statisztikához kapcsolódó változással meg lesz tolva.

7. Következtetés

Ebben a cikkben megismerkedtünk a Java koffein gyorsítótár könyvtárával. Láttuk, hogyan kell konfigurálni és feltölteni a gyorsítótárat, valamint hogyan lehet megfelelő lejárati vagy frissítési házirendet választani az igényeinknek megfelelően.

Az itt látható forráskód elérhető a Githubon.