Introduksjon til salat - Java Redis Client

1. Oversikt

Denne artikkelen er en introduksjon til Lettuce, en Redis Java-klient.

Redis er en nøkkelverdilager i minnet som kan brukes som database, cache eller meldingsmegler. Data legges til, spørres, modifiseres og slettes med kommandoer som fungerer på tastene i Redis 'datastruktur i minnet.

Salat støtter både synkron og asynkron kommunikasjonsbruk av den komplette Redis API, inkludert datastrukturer, pub / undermeldinger og servertilkoblinger med høy tilgjengelighet.

2. Hvorfor salat?

Vi har dekket Jedis i et av de forrige innleggene. Hva gjør salat annerledes?

Den viktigste forskjellen er dens asynkrone støtte via Java 8-tallet CompletionStage grensesnitt og støtte for Reactive Streams. Som vi vil se nedenfor, tilbyr Salat et naturlig grensesnitt for å komme med asynkrone forespørsler fra Redis-databaseserveren og for å lage strømmer.

Den bruker også Netty for å kommunisere med serveren. Dette gir et "tyngre" API, men gjør det også bedre egnet for å dele en forbindelse med mer enn en tråd.

3. Oppsett

3.1. Avhengighet

La oss starte med å erklære den eneste avhengigheten vi trenger i pom.xml:

 io.salat salatkjerne 5.0.1.RELEASE 

Den siste versjonen av biblioteket kan sjekkes i Github-depotet eller på Maven Central.

3.2. Redis Installasjon

Vi må installere og kjøre minst en forekomst av Redis, to hvis vi ønsker å teste klyngemodus eller sentinel-modus (selv om sentinel-modus krever at tre servere skal fungere riktig.) For denne artikkelen bruker vi 4.0.x - siste stabile versjonen for øyeblikket.

Mer informasjon om å komme i gang med Redis finner du her, inkludert nedlastinger for Linux og MacOS.

Redis støtter ikke offisielt Windows, men det er en port på serveren her. Vi kan også kjøre Redis i Docker, som er et bedre alternativ for Windows 10 og en rask måte å komme i gang.

4. Tilkoblinger

4.1. Koble til en server

Koble til Redis består av fire trinn:

  1. Opprette en Redis URI
  2. Bruke URI for å koble til en RedisClient
  3. Åpne en Redis-tilkobling
  4. Genererer et sett med RedisCommands

La oss se implementeringen:

RedisClient redisClient = RedisClient .create ("redis: // [e-postbeskyttet]: 6379 /"); StatefulRedisConnection-tilkobling = redisClient.connect ();

EN StatefulRedisConnection er hvordan det høres ut; en trådsikker tilkobling til en Redis-server som vil opprettholde forbindelsen til serveren og koble til igjen om nødvendig. Når vi har en forbindelse, kan vi bruke den til å utføre Redis-kommandoer enten synkront eller asynkront.

RedisClient bruker betydelige systemressurser, da den har Netty-ressurser for å kommunisere med Redis-serveren. Programmer som krever flere tilkoblinger, bør bruke en enkelt RedisClient.

4.2. Redis URI

Vi lager en RedisClient ved å sende en URI til den statiske fabrikkmetoden.

Salat utnytter en tilpasset syntaks for Redis URI. Dette er skjemaet:

redis: // [[email protected]] vert [: port] [/ database] [? [timeout = timeout [d | h | m | s | ms | us | ns]] [& _database = database_]] 

Det er fire URI-ordninger:

  • redis - en frittstående Redis-server
  • rediss - en frittstående Redis-server via en SSL-tilkobling
  • redis-stikkontakt - en frittstående Redis-server via et Unix-domeneuttak
  • redis-sentinel - en Redis Sentinel-server

Redis-databaseforekomsten kan spesifiseres som en del av URL-banen eller som en ekstra parameter. Hvis begge leveres, har parameteren høyere prioritet.

I eksemplet ovenfor bruker vi a String representasjon. Salat har også en RedisURI klasse for å bygge forbindelser. Det tilbyr Bygger mønster:

RedisURI.Builder .redis ("localhost", 6379) .auth ("password") .database (1) .build (); 

Og en konstruktør:

nye RedisURI ("localhost", 6379, 60, TimeUnit.SECONDS); 

4.3. Synkrone kommandoer

I likhet med Jedis gir Lettuce et komplett Redis-kommandosett i form av metoder.

Imidlertid implementerer Salat både synkron og asynkron versjon. Vi vil se på den synkrone versjonen kort, og deretter bruke den asynkrone implementeringen for resten av opplæringen.

Etter at vi har opprettet en forbindelse, bruker vi den til å lage et kommandosett:

RedisCommands syncCommands = connection.sync (); 

Nå har vi et intuitivt grensesnitt for å kommunisere med Redis.

Vi kan sette og få Strengverdier:

syncCommands.set ("nøkkel", "Hei, Redis!"); Strengverdi = syncommands.get (“nøkkel”); 

Vi kan jobbe med hashes:

syncCommands.hset ("recordName", "FirstName", "John"); syncCommands.hset ("recordName", "LastName", "Smith"); Map record = syncCommands.hgetall ("recordName"); 

Vi vil dekke flere Redis senere i artikkelen.

Salat synkron API bruker asynkron API. Blokkering gjøres for oss på kommandonivå. Dette betyr at mer enn én klient kan dele en synkron forbindelse.

4.4. Asynkrone kommandoer

La oss ta en titt på de asynkrone kommandoene:

RedisAsyncCommands asyncCommands = connection.async (); 

Vi henter et sett med RedisAsyncCommands fra tilkoblingen, i likhet med hvordan vi hentet det synkrone settet. Disse kommandoene returnerer a RedisFuture (hvilken er en Fullførbar fremtid internt):

RedisFuture-resultat = asyncCommands.get ("nøkkel"); 

En guide til å jobbe med en Fullførbar fremtid finner du her.

4.5. Reaktivt API

Til slutt, la oss se hvordan vi kan arbeide med ikke-blokkerende reaktivt API:

RedisStringReactiveCommands reactiveCommands = connection.reactive (); 

Disse kommandoene gir resultater innpakket i a Mono eller a Flux fra Project Reactor.

En guide til å jobbe med Project Reactor finner du her.

5. Redis datastrukturer

Vi så kort på strenger og hashes ovenfor, la oss se på hvordan Salat implementerer resten av Redis datastrukturer. Som vi forventer, har hver Redis-kommando en lignende navn.

5.1. Lister

Lister er lister over Strenger med rekkefølgen for innsetting bevart. Verdier settes inn eller hentes fra begge sider:

asyncCommands.lpush ("oppgaver", "første oppgave"); asyncCommands.lpush ("oppgaver", "secondTask"); RedisFuture redisFuture = asyncCommands.rpop ("oppgaver"); Streng neste oppgave = redisFuture.get (); 

I dette eksemplet, neste oppgave er lik "første oppgave“. Lpush skyver verdier til hodet på listen, og deretter rpop popper verdier fra slutten av listen.

Vi kan også pope elementer fra den andre enden:

asyncCommands.del ("oppgaver"); asyncCommands.lpush ("oppgaver", "første oppgave"); asyncCommands.lpush ("oppgaver", "secondTask"); redisFuture = asyncCommands.lpop ("oppgaver"); Streng neste oppgave = redisFuture.get (); 

Vi starter det andre eksemplet med å fjerne listen med del. Så setter vi inn de samme verdiene igjen, men vi bruker lpop for å poppe verdiene fra hodet på listen, slik at neste oppgave holder "secondTask”Tekst.

5.2. Settene

Redis sett er uordnede samlinger av Strenger ligner Java Settene; det er ingen dupliserte elementer:

asyncCommands.sadd ("kjæledyr", "hund"); asyncCommands.sadd ("kjæledyr", "katt"); asyncCommands.sadd ("kjæledyr", "katt"); RedisFuture pets = asyncCommands.smembers ("kallenavn"); RedisFuture eksisterer = asyncCommands.sismember ("kjæledyr", "hund"); 

Når vi henter Redis-settet som en Sett, størrelsen er to, siden duplikatet "katt" ble ignorert. Når vi spør Redis om eksistensen av "hund" med sismember, svaret er ekte.

5.3. Hashes

Vi så kort på et eksempel på hasj tidligere. De er verdt en rask forklaring.

Redis Hashes er poster med String felt og verdier. Hver post har også en nøkkel i den primære indeksen:

asyncCommands.hset ("recordName", "FirstName", "John"); asyncCommands.hset ("recordName", "LastName", "Smith"); RedisFuture etternavn = syncCommands.hget ("postnavn", "Etternavn"); RedisFuture post = syncCommands.hgetall ("recordName"); 

Vi bruker hset for å legge til felt i hasjen, ved å sende inn navnet på hasjen, navnet på feltet og en verdi.

Deretter henter vi en individuell verdi med hget, navnet på posten og feltet. Til slutt henter vi hele plata som en hasj med hgetall.

5.4. Sorterte sett

Sorterte sett inneholder verdier og en rangering som de sorteres etter. Rangeringen er 64-bits flytende verdi.

Elementer legges til med rangering og hentes i et område:

asyncCommands.zadd ("sortedset", 1, "one"); asyncCommands.zadd ("sortedset", 4, "zero"); asyncCommands.zadd ("sortedset", 2, "two"); RedisFuture valuesForward = asyncCommands.zrange (nøkkel, 0, 3); RedisFuture valuesReverse = asyncCommands.zrevrange (nøkkel, 0, 3); 

Det andre argumentet til zadd er en rang. Vi henter et område etter rang med zrange for stigende rekkefølge og zrangerte for nedstigning.

Vi la til “null”Med rangering 4, så det vises på slutten av verdier fremover og i begynnelsen av verdier Omvendt.

6. Transaksjoner

Transaksjoner tillater utførelse av et sett med kommandoer i et enkelt atomsteg. Disse kommandoene blir garantert utført i rekkefølge og eksklusivt. Kommandoer fra en annen bruker blir ikke utført før transaksjonen er ferdig.

Enten utføres alle kommandoer, eller ingen av dem. Redis utfører ikke tilbakestilling hvis en av dem mislykkes. En gang utføre () kalles, blir alle kommandoer utført i den angitte rekkefølgen.

La oss se på et eksempel:

asyncCommands.multi (); RedisFuture result1 = asyncCommands.set ("key1", "value1"); RedisFuture result2 = asyncCommands.set ("key2", "value2"); RedisFuture result3 = asyncCommands.set ("key3", "value3"); RedisFuture execResult = asyncCommands.exec (); TransactionResult transactionResult = execResult.get (); Streng firstResult = transactionResult.get (0); Streng secondResult = transactionResult.get (0); Streng thirdResult = transactionResult.get (0); 

Oppfordringen til multi starter transaksjonen. Når en transaksjon startes, blir de påfølgende kommandoene ikke utført før utføre () er kalt.

I synkron modus kommer kommandoene tilbake null. I asynkron modus kommer kommandoene tilbake RedisFuture . Utfør returnerer a TransactionResult som inneholder en liste over svar.

Siden RedisFutures mottar også resultatene, asynkrone API-klienter mottar transaksjonsresultatet to steder.

7. Batching

Under normale forhold utfører Salat kommandoer så snart de blir ringt opp av en API-klient.

Dette er hva de fleste vanlige applikasjoner vil ha, spesielt hvis de stoler på å motta kommandoresultater serielt.

Denne oppførselen er imidlertid ikke effektiv hvis applikasjoner ikke trenger resultater umiddelbart eller hvis store mengder data blir lastet opp i bulk.

Asynkrone applikasjoner kan overstyre denne oppførselen:

commands.setAutoFlushCommands (false); Liste futures = ny ArrayList (); for (int i = 0; i <iterasjoner; i ++) {futures.add (commands.set ("key-" + i, "value-" + i);} commands.flushCommands (); boolean result = LettuceFutures.awaitAll (5, TimeUnit.SECONDS, futures.toArray (ny RedisFuture [0])); 

Med setAutoFlushCommands satt til falsk, må søknaden ringe flushCommands manuelt. I dette eksemplet stod vi flere i kø sett kommandoen og spylte deretter kanalen. AwaitAll venter på alle RedisFutures å fullføre.

Denne tilstanden er satt per tilkoblingsbasis og påvirker alle tråder som bruker tilkoblingen. Denne funksjonen gjelder ikke for synkrone kommandoer.

8. Publiser / Abonner

Redis tilbyr et enkelt meldingssystem for publisering / abonnement. Abonnenter bruker meldinger fra kanaler med abonnere kommando. Meldinger er ikke vedvarende; de leveres bare til brukere når de abonnerer på en kanal.

Redis bruker pub / sub-systemet for varsler om Redis datasettet, noe som gir klienter muligheten til å motta hendelser om at nøkler blir satt, slettet, utløpt, etc.

Se dokumentasjonen her for mer informasjon.

8.1. Abonnent

EN RedisPubSubListener mottar pub / undermeldinger. Dette grensesnittet definerer flere metoder, men vi viser bare metoden for å motta meldinger her:

public class Listener implementerer RedisPubSubListener {@Override public void message (String channel, String message) {log.debug ("Got {} on channel {}", melding, kanal); melding = ny streng (s2); }} 

Vi bruker RedisClient for å koble til en pub / underkanal og installere lytteren:

StatefulRedisPubSubConnection connection = client.connectPubSub (); connection.addListener (new Listener ()) RedisPubSubAsyncCommands async = connection.async (); async.subscribe ("kanal"); 

Med en lytter installert, henter vi et sett med RedisPubSubAsyncCommands og abonner på en kanal.

8.2. Forlegger

Publisering er bare et spørsmål om å koble til en Pub / Sub-kanal og hente kommandoene:

StatefulRedisPubSubConnection connection = client.connectPubSub (); RedisPubSubAsyncCommands async = connection.async (); async.publish ("kanal", "Hei, Redis!"); 

Publisering krever en kanal og en melding.

8.3. Reaktive abonnementer

Salat tilbyr også et reaktivt grensesnitt for å abonnere på pub / undermeldinger:

StatefulRedisPubSubConnection-tilkobling = klient .connectPubSub (); RedisPubSubAsyncCommands reaktiv = tilkobling .reaktiv (); reactive.observeChannels (). abonner (melding -> {log.debug ("Fikk {} på kanal {}", melding, kanal); melding = ny streng (s2);}); reactive.subscribe ("kanal"). subscribe (); 

De Flux returnert av observer kanaler mottar meldinger for alle kanaler, men siden dette er en strøm, er det enkelt å filtrere.

9. Høy tilgjengelighet

Redis tilbyr flere alternativer for høy tilgjengelighet og skalerbarhet. Fullstendig forståelse krever kunnskap om Redis-serverkonfigurasjoner, men vi vil gå over en kort oversikt over hvordan Salat støtter dem.

9.1. Master / Slave

Redis-servere replikerer seg selv i en master / slave-konfigurasjon. Hovedserveren sender slaven en strøm av kommandoer som replikerer hovedbufferen til slaven. Redis støtter ikke toveis replikering, så slaver er skrivebeskyttet.

Salat kan koble til Master / Slave-systemer, spørre dem om topologien, og deretter velge slaver for leseoperasjoner, noe som kan forbedre gjennomstrømningen:

RedisClient redisClient = RedisClient.create (); StatefulRedisMasterSlaveConnection connection = MasterSlave.connect (redisClient, ny Utf8StringCodec (), RedisURI.create ("redis: // localhost")); connection.setReadFrom (ReadFrom.SLAVE); 

9.2. vakt

Redis Sentinel overvåker mester- og slaveforekomster og orkestrerer failover til slaver i tilfelle en master failover.

Salat kan koble til Sentinel, bruke den til å oppdage adressen til den gjeldende mesteren, og deretter returnere en forbindelse til den.

For å gjøre dette bygger vi en annen RedisURI og koble vårt RedisClient med det:

RedisURI redisUri = RedisURI.Builder .sentinel ("sentinelhost1", "clustername") .withSentinel ("sentinelhost2"). Build (); RedisClient-klient = ny RedisClient (redisUri); RedisConnection-tilkobling = client.connect (); 

Vi bygde URI med vertsnavnet (eller adressen) til den første Sentinel og et klyngenavn, etterfulgt av en andre sentinel-adresse. Når vi kobler oss til Sentinel, spør Salat det om topologien og returnerer en forbindelse til den nåværende masterserveren for oss.

Den komplette dokumentasjonen er tilgjengelig her.

9.3. Klynger

Redis Cluster bruker en distribuert konfigurasjon for å gi høy tilgjengelighet og høy gjennomstrømning.

Klynger splitter nøkler over opptil 1000 noder, derfor er transaksjoner ikke tilgjengelige i en klynge:

RedisURI redisUri = RedisURI.Builder.redis ("localhost") .withPassword ("authentication"). Build (); RedisClusterClient clusterClient = RedisClusterClient .create (rediUri); StatefulRedisClusterConnection connection = clusterClient.connect (); RedisAdvancedClusterCommands syncCommands = tilkobling. Sync (); 

RedisAdvancedClusterCommands holder settet med Redis-kommandoer som støttes av klyngen, og dirigerer dem til forekomsten som inneholder nøkkelen.

En komplett spesifikasjon er tilgjengelig her.

10. Konklusjon

I denne opplæringen så vi på hvordan vi bruker salat til å koble til og spørre en Redis-server fra applikasjonen vår.

Salat støtter hele settet med Redis-funksjoner, med bonusen på et helt trådsikkert asynkront grensesnitt. Det bruker også omfattende bruk av Java 8-er CompletionStage grensesnitt for å gi applikasjoner finkornet kontroll over hvordan de mottar data.

Kodeeksempler, som alltid, kan du finne på GitHub.


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