Key Value Store med Chronicle Map

1. Oversikt

I denne opplæringen skal vi se hvordan vi kan bruke Chronicle Map for å lagre nøkkelverdipar. Vi skal også lage korte eksempler for å demonstrere atferd og bruk.

2. Hva er et kronikkart?

Etter dokumentasjonen, “Chronicle Map er en superrask, ikke-blokkerende, nøkkelverdilager i minnet, designet for applikasjoner med lav latens og / eller flerprosess”.

I et nøtteskall er det en off-heap nøkkelverdibutikk. Kartet krever ikke mye RAM for at det skal fungere skikkelig. Den kan vokse basert på tilgjengelig diskkapasitet. Videre støtter den replikering av dataene i et multi-master serveroppsett.

La oss nå se hvordan vi kan sette opp og jobbe med det.

3. Maven avhengighet

For å komme i gang, må vi legge til kronikk-kartavhengighet til prosjektet vårt:

 net.openhft kronikk-kart 3.17.2 

4. Typer av kronikkart

Vi kan lage et kart på to måter: enten som et minnekart eller som et vedvarende kart.

La oss se begge disse i detalj.

4.1. Kart over minne

En in-memory Chronicle Map er en kartbutikk som opprettes i serverens fysiske minne. Dette betyr den er bare tilgjengelig innenfor JVM-prosessen der kartbutikken er opprettet.

La oss se et raskt eksempel:

ChronicleMap inMemoryCountryMap = ChronicleMap .of (LongValue.class, CharSequence.class) .name ("country-map") .entries (50) .averageValue ("America") .create ();

For enkelhets skyld lager vi et kart som lagrer 50 land-ID-er og navnene deres. Som vi kan se i kodebiten, er opprettelsen ganske grei bortsett fra gjennomsnittlig verdi() konfigurasjon. Dette forteller kartet å konfigurere det gjennomsnittlige antall byte tatt av verdiene for kartoppføringen.

Med andre ord, når du oppretter kartet, bestemmer Chronicle Map det gjennomsnittlige antall byte tatt av den serielle formen av verdier. Den gjør dette ved å serialisere den gitte gjennomsnittsverdien ved hjelp av de konfigurerte verdibeskytterne. Den vil deretter tildele det bestemte antall byte for verdien av hver kartoppføring.

En ting vi må merke oss når det kommer til minnekartet, er at dataene bare er tilgjengelige når JVM-prosessen er i live. Biblioteket vil tømme dataene når prosessen avsluttes.

4.2. Vedvarende kart

I motsetning til et kart i minnet, implementeringen vil lagre et vedvarende kart på disken. La oss nå se hvordan vi kan lage et vedvarende kart:

ChronicleMap persistedCountryMap = ChronicleMap .of (LongValue.class, CharSequence.class) .name ("country-map"). Entries (50) .averageValue ("America") .createPersistedTo (new File (System.getProperty ("user.home) ") +" /country-details.dat "));

Dette vil opprette en fil som heter land-detaljer.dat i den angitte mappen. Hvis denne filen allerede er tilgjengelig i den angitte banen, vil byggherreimplementeringen åpne en lenke til det eksisterende datalageret fra denne JVM-prosessen.

Vi kan bruke det vedvarende kartet i tilfeller der vi vil at det skal:

  • overleve utover skaperprosessen; for eksempel for å støtte omplassering av varm applikasjon
  • gjøre det globalt på en server; for eksempel for å støtte flere samtidige prosesstilgang
  • fungere som et datalager som vi lagrer på disken

5. Størrelseskonfigurasjon

Det er obligatorisk å konfigurere gjennomsnittsverdien og gjennomsnittsnøkkelen mens du oppretter et kronikkart, bortsett fra i tilfelle der nøkkel- / verditypen vår enten er en primitiv boks eller et verdigrensesnitt. I vårt eksempel konfigurerer vi ikke gjennomsnittstasten siden nøkkeltypen LongValue er et grensesnitt for verdier.

La oss nå se hva alternativene er for å konfigurere gjennomsnittlig antall nøkkel- / verdibytes:

  • gjennomsnittlig verdi() - Verdien som det gjennomsnittlige antall byte som skal tildeles for verdien av en kartoppføring bestemmes fra
  • averageValueSize () - Gjennomsnittlig antall byte som skal tildeles for verdien av en kartoppføring
  • constantValueSizeBySample () - Antall byte som skal tildeles for verdien av en kartoppføring når størrelsen på verdien alltid er den samme
  • averageKey () - Nøkkelen hvor det gjennomsnittlige antall byte som skal tildeles for nøkkelen til en kartoppføring bestemmes
  • averageKeySize () - Gjennomsnittlig antall byte som skal tildeles for nøkkelen til en kartoppføring
  • constantKeySizeBySample () - Antall byte som skal tildeles for nøkkelen til en kartoppføring når størrelsen på nøkkelen alltid er den samme

6. Nøkkel- og verdityper

Det er visse standarder som vi må følge når vi lager et kronikkart, spesielt når vi definerer nøkkel og verdi. Kartet fungerer best når vi lager nøkkelen og verdien ved hjelp av de anbefalte typene.

Her er noen av de anbefalte typene:

  • Verdi grensesnitt
  • Enhver klasse som implementerer Byteable grensesnitt fra Chronicle Bytes
  • Enhver klasse som implementeres BytesMarshallable grensesnitt fra Chronicle Bytes; implementeringsklassen skal ha en offentlig ikke-arg-konstruktør
  • byte [] og ByteBuffer
  • CharSequence, String, og StringBuilder
  • Heltall, Lang, og Dobbelt
  • Enhver klasse som implementeres java.io. kan utvides; implementeringsklassen skal ha en offentlig ikke-arg-konstruktør
  • Enhver type implementering java.io Serialiserbar, inkludert primitive typer i boks (unntatt de som er oppført ovenfor) og matrityper
  • Enhver annen type, hvis tilpassede serielliserere er gitt

7. Spørring av et kronikkart

Chronicle Map støtter enkle nøkkel-spørsmål så vel som flere nøkkel-spørsmål.

7.1. Enkeltnøkkelspørringer

Enkeltnøkkel-spørsmål er operasjonene som omhandler en enkelt nøkkel. ChronicleMap støtter alle operasjoner fra Java Kart grensesnitt og ConcurrentMap grensesnitt:

LongValue qatarKey = Verdier.newHeapInstance (LongValue.class); qatarKey.setValue (1); inMemoryCountryMap.put (qatarKey, "Qatar"); // ... CharSequence country = inMemoryCountryMap.get (key);

I tillegg til den vanlige get and put-operasjonen, ChronicleMap legger til en spesiell operasjon, getUsing (), som reduserer minnefotavtrykket mens du henter og behandler en oppføring. La oss se dette i aksjon:

LongValue-nøkkel = Verdier.newHeapInstance (LongValue.class); StringBuilder country = new StringBuilder (); key.setValue (1); persistedCountryMap.getUsing (nøkkel, land); assertThat (country.toString (), er (equalTo ("Romania"))); key.setValue (2); persistedCountryMap.getUsing (nøkkel, land); assertThat (country.toString (), er (equalTo ("India")));

Her har vi brukt det samme StringBuilder objekt for å hente verdier for forskjellige nøkler ved å sende det til getUsing () metode. Det bruker i utgangspunktet det samme objektet for å hente forskjellige oppføringer. I vårt tilfelle er getUsing () metoden tilsvarer:

country.setLength (0); country.append (persistedCountryMap.get (key));

7.2. Multi-Key-spørsmål

Det kan være brukstilfeller der vi trenger å håndtere flere nøkler samtidig. For dette kan vi bruke queryContext () funksjonalitet. De queryContext () metoden vil skape en kontekst for arbeid med en kartoppføring.

La oss først lage et multikart og legge til noen verdier i det:

Sett gjennomsnittsverdi = IntStream.of (1, 2) .boxed (). Collect (Collectors.toSet ()); ChronicleMap multiMap = ChronicleMap .of (Integer.class, (Class) (Class) Set.class) .name ("multi-map") .posts (50) .averageValue (averageValue) .create (); Sett sett1 = nytt HashSet (); set1.add (1); set1.add (2); multiMap.put (1, set1); Sett set2 = nytt HashSet (); set2.add (3); multiMap.put (2, set2);

For å jobbe med flere oppføringer, må vi låse disse oppføringene for å forhindre inkonsekvens som kan oppstå på grunn av en samtidig oppdatering:

prøv (ExternalMapQueryContext var13 -> fistContext = multiMap.queryContext (1)) {try (ExternalMapQueryContext var13 -> secondContext = multiMap.queryContext (2)) {fistContext.updateLock (). lock (); secondContext.updateLock (). lås (); MapEntry firstEntry = fistContext.entry (); Sett firstSet = firstEntry.value (). Get (); firstSet.remove (2); MapEntry secondEntry = secondContext.entry (); Sett secondSet = secondEntry.value (). Get (); secondSet.add (4); firstEntry.doReplaceValue (fistContext.wrapValueAsData (firstSet)); secondEntry.doReplaceValue (secondContext.wrapValueAsData (secondSet)); }} til slutt {assertThat (multiMap.get (1) .størrelse (), er (equalTo (1))); assertThat (multiMap.get (2) .størrelse (), er (equalTo (2))); }

8. Lukking av kronikkartet

Nå som vi er ferdig med å jobbe med kartene våre, la oss kalle Lukk() -metoden på kartobjektene våre for å frigjøre off-heap-minnet og ressursene som er knyttet til det:

persistedCountryMap.close (); inMemoryCountryMap.close (); multiMap.close ();

En ting å huske på her er at alle kartoperasjonene må være fullført før kartet lukkes. Ellers kan JVM krasje uventet.

9. Konklusjon

I denne opplæringen har vi lært hvordan vi bruker et kronikkart til å lagre og hente nøkkelverdipar. Selv om fellesskapsversjonen er tilgjengelig med de fleste av kjernefunksjonalitetene, har den kommersielle versjonen noen avanserte funksjoner som datareplikering på tvers av flere servere og eksterne samtaler.

Alle eksemplene vi har diskutert her finner du i Github-prosjektet.


$config[zx-auto] not found$config[zx-overlay] not found