Útmutató az Java-ban található Infinispanhoz

1. Áttekintés

Ebben az útmutatóban megtudhatjuk az Infinispan-t, egy memóriában lévő kulcs / érték adattárolót, amely robusztusabb funkciókkal rendelkezik, mint ugyanazon rés többi eszköze.

A működésének megértése érdekében elkészítünk egy egyszerű projektet, amely bemutatja a leggyakoribb jellemzőket, és ellenőrzi, hogyan használhatók.

2. Projekt beállítása

Ahhoz, hogy ezt így tudjuk használni, hozzá kell adnunk a függőséget a sajátunkban pom.xml.

A legújabb verzió megtalálható a Maven Central adattárban:

 org.infinispan infinispan-core 9.1.5.Döntő 

Az összes szükséges mögöttes infrastruktúrát ezentúl programozottan kezeljük.

3. CacheManager Beállít

A CacheManager az általunk használt funkciók többségének alapja. Konténerként működik az összes bejelentett gyorsítótár számára, ellenőrzi azok életciklusát, és felelős a globális konfigurációért.

Az Infinispan nagyon egyszerű módon szállítja a hajót CacheManager:

public DefaultCacheManager cacheManager () {return new DefaultCacheManager (); }

Most kiépíthetjük vele a gyorsítótárakat.

4. Gyorsítótárak beállítása

A gyorsítótárat egy név és egy konfiguráció határozza meg. Az osztály segítségével felépíthető a szükséges konfiguráció ConfigurationBuilder, már elérhető az osztályúton.

A gyorsítótárak teszteléséhez létrehozunk egy egyszerű módszert, amely néhány nehéz lekérdezést szimulál:

public class HelloWorldRepository {public String getHelloWorld () {try {System.out.println ("Néhány nehéz lekérdezés végrehajtása"); Szál.alszik (1000); } catch (InterruptedException e) {// ... e.printStackTrace (); } return "Hello World!"; }}

Továbbá, hogy ellenőrizni tudjuk a gyorsítótárunkban bekövetkezett változásokat, az Infinispan egyszerű feljegyzéssel szolgál @Hallgató.

A gyorsítótárunk definiálásakor átadhatunk néhány objektumot, amely érdekli a benne zajló eseményeket, és az Infinispan értesíti a gyorsítótár kezeléséről:

@Listener public class CacheListener {@CacheEntryCreated public void entryCreated (CacheEntryCreatedEvent event) {this.printLog ("Kulcs hozzáadása" + esemény.getKey () + "'a gyorsítótárhoz", esemény); } @CacheEntryExpired public void entryExpired (CacheEntryExpiredEvent event) {this.printLog ("Lejáró kulcs" "+ event.getKey () +" 'a gyorsítótárból ", esemény); } @CacheEntryVisited public void entryVisited (CacheEntryVisitedEvent event) {this.printLog ("Key" "+ event.getKey () +" 'meglátogatták ", esemény); } @CacheEntryActivated public void entryActivated (CacheEntryActivatedEvent event) {this.printLog ("Aktiváló kulcs" "+ event.getKey () +" 'a gyorsítótárban ", esemény); } @CacheEntryPassivated public void entryPassivated (CacheEntryPassivatedEvent event) {this.printLog ("Passziváló kulcs" "+ esemény.getKey () +" 'a gyorsítótárból ", esemény); } @CacheEntryLoaded public void entryLoaded (CacheEntryLoadedEvent event) {this.printLog ("Kulcs betöltése" + event.getKey () + "'a gyorsítótárba", esemény); } @CacheEntriesEvicted public void recordsEvicted (CacheEntriesEvictedEvent esemény) {StringBuilder builder = new StringBuilder (); event.getEntries (). forEach ((kulcs, érték) -> builder.append (kulcs) .append (",")); System.out.println ("A következő bejegyzések kiürítése a gyorsítótárból:" + builder.toString ()); } private void printLog (String napló, CacheEntryEvent esemény) {if (! event.isPre ()) {System.out.println (log); }}}

Üzenetünk kinyomtatása előtt ellenőrizzük, hogy megtörtént-e már az értesítendő esemény, mert egyes eseménytípusok esetében az Infinispan két értesítést küld: egyet a feldolgozás előtt és egy után.

Most készítsünk egy módszert a gyorsítótár létrehozásának számunkra kezelésére:

privát gyorsítótár buildCache (karakterlánc cacheName, DefaultCacheManager cacheManager, CacheListener figyelő, konfigurációs konfiguráció) {cacheManager.defineConfiguration (cacheName, konfiguráció); Cache cache = cacheManager.getCache (cacheName); cache.addListener (figyelő); return cache; }

Figyelje meg, hogyan adunk át egy konfigurációt CacheManager, majd használja ugyanazt cacheName hogy megkapja a kívánt gyorsítótárnak megfelelő objektumot. Vegye figyelembe azt is, hogyan tájékoztatjuk a hallgatót magáról a gyorsítótár objektumról.

Most ellenőrzünk öt különböző gyorsítótár-konfigurációt, és meglátjuk, hogyan állíthatjuk be őket, és hogyan használhatjuk ki őket a legjobban.

4.1. Egyszerű gyorsítótár

A legegyszerűbb típusú gyorsítótár egy módszerrel határozható meg egy sorban buildCache:

public Cache simpleHelloWorldCache (DefaultCacheManager cacheManager, CacheListener hallgató) {return this.buildCache (SIMPLE_HELLO_WORLD_CACHE, cacheManager, figyelő, új ConfigurationBuilder (). build ()); }

Most építhetünk egy Szolgáltatás:

public String findSimpleHelloWorld () {String cacheKey = "egyszerű-hello"; return simpleHelloWorldCache .computeIfAbsent (cacheKey, k -> repository.getHelloWorld ()); }

Vegye figyelembe, hogy miként használjuk a gyorsítótárat, először ellenőrizze, hogy a kívánt bejegyzés már van-e gyorsítótárban. Ha nem, akkor fel kell hívnunk a telefonunkat Adattár majd tárolja.

Vegyünk egy egyszerű módszert tesztjeinkbe a módszerek időzítésére:

védett hosszú időThis (Szállítói beszállító) {long millis = System.currentTimeMillis (); beszállító.get (); return System.currentTimeMillis () - millisz; }

Tesztelésével ellenőrizhetjük a két módszerhívás végrehajtása közötti időt:

@Test public void whenGetIsCalledTwoTimes_thenTheSecondShouldHitTheCache () {assertThat (timeThis (() -> helloWorldService.findSimpleHelloWorld ())) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findSimpleHelloWorld ())) .isLessThan (100); }

4.2. Lejárati gyorsítótár

Meghatározhatunk egy gyorsítótárat, amelyben az összes bejegyzés élettartama van, más szóval, az elemeket egy adott időszak után eltávolítjuk a gyorsítótárból. A konfigurálás meglehetősen egyszerű:

privát konfiguráció expiringConfiguration () {return new ConfigurationBuilder (). expiration () .lifespan (1, TimeUnit.SECONDS) .build (); }

Most a fenti konfiguráció segítségével építjük fel a gyorsítótárunkat:

public Cache expiringHelloWorldCache (DefaultCacheManager cacheManager, CacheListener listener) {return this.buildCache (EXPIRING_HELLO_WORLD_CACHE, cacheManager, figyelő, expiringConfiguration ()); }

És végül használja a fenti egyszerű gyorsítótárunk hasonló módszerével:

public String findSimpleHelloWorldInExpiringCache () {String cacheKey = "egyszerű-hello"; Karakterlánc helloWorld = expiringHelloWorldCache.get (cacheKey); if (helloWorld == null) {helloWorld = adattár.getHelloWorld (); lejáróHelloWorldCache.put (cacheKey, helloWorld); } return helloWorld; }

Teszteljük újra az időnket:

@Test public void whenGetIsCalledTwoTimesQuickly_thenTheSecondShouldHitTheCache () {assertThat (timeThis (() -> helloWorldService.findExpiringHelloWorld ())) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findExpiringHelloWorld ())) .isLessThan (100); }

Futtatva azt látjuk, hogy gyors egymásutánban a gyorsítótár elér. Annak bemutatására, hogy a lejárat viszonyul-e a bejegyzéshez tedd idővel erőltessük a bejegyzésünkben:

@Test public void whenGetIsCalledTwiceSparsely_thenNeitherHitsTheCache () dob InterruptedException {assertThat (timeThis (() -> helloWorldService.findExpiringHelloWorld ())) .isGreaterThanOrEqualTo () Szál.alszik (1100); assertThat (timeThis (() -> helloWorldService.findExpiringHelloWorld ())) .isGreaterThanOrEqualTo (1000); }

A teszt futtatása után vegye figyelembe, hogy a megadott idő után hogyan telt le a bejegyzésünk a gyorsítótárból. Ezt megerősíthetjük, ha megnézzük hallgatónk nyomtatott naplósorait:

Néhány nehéz lekérdezés végrehajtása Az 'egyszerű-hello' kulcs hozzáadása a gyorsítótárhoz Az 'egyszerű-hello' kulcs lejárta a gyorsítótárból Néhány nehéz lekérdezés végrehajtása Az 'egyszerű-hello' kulcs hozzáadása a gyorsítótárhoz

Vegye figyelembe, hogy a bejegyzés lejárt, amikor megpróbáljuk elérni. Az Infinispan két pillanat alatt ellenőrzi a lejárt bejegyzést: amikor megpróbálunk hozzáférni hozzá, vagy amikor az arató szál beolvassa a gyorsítótárat.

A lejáratot még a gyorsítótárakban is felhasználhatjuk anélkül, hogy a fő konfigurációban lennének. A módszer, a metódus tedd további érveket fogad el:

simpleHelloWorldCache.put (cacheKey, helloWorld, 10, TimeUnit.SECONDS);

Vagy rögzített élettartam helyett maximálisan megadhatjuk a belépésünket holtidő:

simpleHelloWorldCache.put (cacheKey, helloWorld, -1, TimeUnit.SECONDS, 10, TimeUnit.SECONDS);

-1-et használva az élettartam attribútumhoz, a gyorsítótár nem szenved lejáratot tőle, de ha 10 másodperces holtidő, azt mondjuk az Infinispannak, hogy járjon le ennek a bejegyzésnek, hacsak nem ebben az időkeretben keresi fel.

4.3. Gyorsítótár kiürítése

Az Infinispan alkalmazásban korlátozhatjuk a bejegyzések számát egy adott gyorsítótárban a kilakoltatás konfigurációja:

privát konfiguráció evictingConfiguration () {return new ConfigurationBuilder () .memory (). evictionType (EvictionType.COUNT) .size (1) .build (); }

Ebben a példában a gyorsítótár maximális bejegyzését egyre korlátozzuk, ami azt jelenti, hogy ha megpróbálunk másikat beírni, akkor kiürül a gyorsítótárunkból.

A módszer megint hasonló az itt már bemutatotthoz:

public String findEvictingHelloWorld (karakterlánc-kulcs) {String value = evictingHelloWorldCache.get (kulcs); if (érték == null) {érték = adattár.getHelloWorld (); evictingHelloWorldCache.put (kulcs, érték); } visszatérési érték; }

Készítsük el tesztünket:

@Test public void whenTwoAreAdded_thenFirstShouldntBeAvailable () {assertThat (timeThis (() -> helloWorldService.findEvictingHelloWorld ("kulcs 1"))) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findEvictingHelloWorld ("2. kulcs")))) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findEvictingHelloWorld ("1. kulcs"))) .isGreaterThanOrEqualTo (1000); }

A teszt futtatása során megnézhetjük a hallgatók tevékenységnaplóját:

Néhány nehéz lekérdezés végrehajtása Az „1-es kulcs” kulcs hozzáadása a gyorsítótárhoz Néhány nehéz lekérdezés végrehajtása A következő bejegyzések kitolása a gyorsítótárból: 1. kulcs, „2-es kulcs” hozzáadása a gyorsítótárhoz Néhány nehéz lekérdezés végrehajtása A következő bejegyzések kitolása a gyorsítótárból: 2. kulcs, Kulcs hozzáadása 1 'a gyorsítótárba

Ellenőrizze, hogy az első kulcs hogyan lett automatikusan eltávolítva a gyorsítótárból, amikor behelyeztük a másodikat, majd a másodikat is eltávolítottuk, hogy ismét helyet kapjunk az első kulcsunknak.

4.4. Passziválási gyorsítótár

A gyorsítótár passziválása az Infinispan egyik erőteljes tulajdonsága. A passziválás és a kilakoltatás kombinálásával létrehozhatunk egy gyorsítótárat, amely nem foglal el sok memóriát, az információk elvesztése nélkül.

Vessünk egy pillantást egy passzivációs konfigurációra:

privát konfiguráció passivatingConfiguration () {return new ConfigurationBuilder () .memory (). evictionType (EvictionType.COUNT) .size (1) .persistence () .passivation (true) // passivation aktiválása .addSingleFileStore () // egyetlen fájlban .purgeOnStartup (true) // a fájl törlése az indításkor .location (System.getProperty ("java.io.tmpdir")) .build (); }

Ismét csak egy bejegyzést kényszerítünk a gyorsítótárunkba, de az Infinispannak azt mondjuk, hogy passziválja a többi bejegyzést ahelyett, hogy csak eltávolítaná őket.

Nézzük meg, mi történik, ha egynél több bejegyzést próbálunk kitölteni:

public String findPassivatingHelloWorld (String kulcs) {return passivatingHelloWorldCache.computeIfAbsent (kulcs, k -> repository.getHelloWorld ()); }

Készítsük el és futtassuk le a tesztünket:

@Test public void whenTwoAreAdded_thenTheFirstShouldBeAvailable () {assertThat (timeThis (() -> helloWorldService.findPassivatingHelloWorld ("kulcs 1"))) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findPassivatingHelloWorld ("2. kulcs")))) .isGreaterThanOrEqualTo (1000); assertThat (timeThis (() -> helloWorldService.findPassivatingHelloWorld ("1. kulcs"))) .isLessThan (100); }

Most nézzük meg hallgatói tevékenységünket:

Néhány nehéz lekérdezés végrehajtása „1-es kulcs” kulcs hozzáadása a gyorsítótárhoz Néhány nehéz lekérdezés végrehajtása Az „1-es kulcs” kulcs passziválása a gyorsítótárból A következő bejegyzések kitiltása a gyorsítótárból: 1. kulcs, „2-es” kulcs hozzáadása a gyorsítótárhoz A „2-es kulcs” kulcs passziválása a gyorsítótárból a következő bejegyzések a gyorsítótárból: 2. kulcs, az „1-es kulcs” kulcs betöltése a gyorsítótárba Az „1-es kulcs” kulcs aktiválása a gyorsítótárban

Vegye figyelembe, hogy hány lépés történt a gyorsítótárunk egyetlen bejegyzéssel történő megtartása érdekében. Vegye figyelembe a lépések sorrendjét is - passziválás, kilakoltatás, majd betöltés, majd aktiválás. Lássuk, mit jelentenek ezek a lépések:

  • Passziválás - bejegyzésünket egy másik helyen tároljuk, távol az Infinispan hálózati tárolójától (ebben az esetben a memóriától)
  • Kilakoltatás - a bejegyzés eltávolításra kerül, hogy felszabaduljon a memória és megtartsuk a bejegyzések maximálisan beállított számát a gyorsítótárban
  • Betöltés - amikor megpróbálja elérni a passzív bejegyzésünket, az Infinispan ellenőrzi a tárolt tartalmat, és újra betölti a bejegyzést a memóriába
  • Aktiválás - a bejegyzés most már ismét elérhető Infinispanban

4.5. Tranzakciós gyorsítótár

Az Infinispan hatékony tranzakció-vezérléssel szállítja. Az adatbázis megfelelőjéhez hasonlóan ez is hasznos az integritás fenntartásában, miközben több szál is megpróbálja ugyanazt a bejegyzést írni.

Nézzük meg, hogyan definiálhatunk gyorsítótárat tranzakciós képességekkel:

privát Configuration transactionalConfiguration () {return new ConfigurationBuilder () .transaction () .actionMode (TransactionMode.TRANSACTIONAL) .lockingMode (LockingMode.PESSIMISTIC) .build (); }

A tesztelésének lehetővé tétele érdekében építsünk két módszert - egyet, amely gyorsan befejezi a tranzakciót, és egyet, amely eltart egy ideig:

public Integer getQuickHowManyVisits () {TransactionManager tm = transactionalCache .getAdvancedCache (). getTransactionManager (); tm.begin (); Egész szám howManyVisits = transactionalCache.get (KEY); howManyVisits ++; System.out.println ("Megpróbálom beállítani a HowManyVisits értékét" + howManyVisits); StopWatch watch = új StopWatch (); watch.start (); transactionalCache.put (KEY, howManyVisits); watch.stop (); System.out.println ("Várakozás után a" HowManyVisits "értéket" + howManyVisits + "értékre állíthattam" + watch.getTotalTimeSeconds () + "másodperc"); tm.vállalás (); return howManyVisits; }
public void startBackgroundBatch () {TransactionManager tm = transactionalCache .getAdvancedCache (). getTransactionManager (); tm.begin (); transactionalCache.put (KEY, 1000); System.out.println ("A HowManyVisits értéke most 1000," + "legyen, de mi tartjuk a tranzakciót"); Szál.alszik (1000L); tm.vissza (); System.out.println ("A lassú tétel visszagurulást szenvedett"); }

Most hozzunk létre egy tesztet, amely mindkét módszert végrehajtja, és ellenőrizzük az Infinispan viselkedését:

@Test public void whenLockingAnEntry_thenItShouldBeInaccessible () dob InterruptedException {Runnable backGroundJob = () -> transactionalService.startBackgroundBatch (); Téma backgroundThread = új szál (backGroundJob); transactionalService.getQuickHowManyVisits (); backgroundThread.start (); Szál.alszik (100); // várjuk, hogy a szálunk felmelegedjen assertThat (timeThis (() -> transactionalService.getQuickHowManyVisits ())) .isGreaterThan (500) .isLessThan (1000); }

Végrehajtása után a következő tevékenységeket látjuk újra a konzolunkon:

A „kulcs” kulcs hozzáadása a gyorsítótárhoz A „kulcs” kulcs meglátogatása megtörtént. Megpróbáltam 1-re állítani a HowManyVisits-t. 0,001 másodperc várakozást követően a HowManyVisits-et 1-re állíthattam, a HowManyVisits-nek most 1000-nek kell lennie, de mi tartjuk a tranzakció-kulcsot. Megpróbálom a HowManyVisits értékét 2-re állítani. A HowManyVisits értékét 2-re állíthattam, miután vártam 0,902 másodpercet. A lassú tétel visszagurulást szenvedett

Ellenőrizze az időt a fő szálon, várva a lassú módszerrel létrehozott tranzakció végét.

5. Következtetés

Ebben a cikkben megnéztük, mi az Infinispan, és vezető funkciókat és képességeket tárol gyorsítótárként egy alkalmazáson belül.

Mint mindig, a kód megtalálható a Githubon.