Introduktion til salat - Java Redis Client

1. Oversigt

Denne artikel er en introduktion til Lettuce, en Redis Java-klient.

Redis er en nøgleværdilager i hukommelsen, der kan bruges som en database, cache eller beskedmægler. Data tilføjes, forespørges, ændres og slettes med kommandoer, der fungerer på tasterne i Redis 'datastruktur i hukommelsen.

Salat understøtter brug af både synkron og asynkron kommunikation af den komplette Redis API, herunder dets datastrukturer, pub / sub-meddelelser og serverforbindelser med høj tilgængelighed.

2. Hvorfor salat?

Vi har dækket Jedis i et af de tidligere indlæg. Hvad gør salat anderledes?

Den mest betydningsfulde forskel er dens asynkrone support via Java 8'erne FuldførelseStage interface og support til Reactive Streams. Som vi ser nedenfor, tilbyder Lettuce en naturlig grænseflade til at fremsætte asynkrone anmodninger fra Redis-databaseserveren og til at oprette streams.

Det bruger også Netty til at kommunikere med serveren. Dette giver en "tungere" API, men gør den også bedre egnet til at dele en forbindelse med mere end en tråd.

3. Opsætning

3.1. Afhængighed

Lad os starte med at erklære den eneste afhængighed, vi har brug for i pom.xml:

 io.salat salatkerne 5.0.1.RELEASE 

Den seneste version af biblioteket kan kontrolleres i Github-arkivet eller på Maven Central.

3.2. Redis installation

Vi bliver nødt til at installere og køre mindst en forekomst af Redis, to, hvis vi ønsker at teste klyngedannelse eller sentinel-tilstand (selvom sentinel-tilstand kræver, at tre servere fungerer korrekt.) Til denne artikel bruger vi 4.0.x - seneste stabile version i øjeblikket.

Flere oplysninger om at komme i gang med Redis kan findes her, herunder downloads til Linux og MacOS.

Redis understøtter ikke officielt Windows, men der er en port på serveren her. Vi kan også køre Redis i Docker, hvilket er et bedre alternativ til Windows 10 og en hurtig måde at komme i gang.

4. Forbindelser

4.1. Oprette forbindelse til en server

Tilslutning til Redis består af fire trin:

  1. Oprettelse af en URI af Redis
  2. Brug af URI til at oprette forbindelse til en RedisClient
  3. Åbning af en Redis-forbindelse
  4. Generere et sæt RedisCommands

Lad os se implementeringen:

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

EN StatefulRedisConnection er, hvordan det lyder; en trådsikker forbindelse til en Redis-server, der opretholder sin forbindelse til serveren og genopretter forbindelse om nødvendigt. Når vi har en forbindelse, kan vi bruge den til at udføre Redis-kommandoer enten synkront eller asynkront.

RedisClient bruger betydelige systemressourcer, da det har Netty-ressourcer til kommunikation med Redis-serveren. Programmer, der kræver flere forbindelser, skal bruge en enkelt RedisClient.

4.2. Redis URI'er

Vi opretter en RedisClient ved at sende en URI til den statiske fabriksmetode.

Salat udnytter en tilpasset syntaks til Redis URI'er. Dette er skemaet:

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

Der er fire URI-ordninger:

  • redis - en uafhængig Redis-server
  • rediss - en standalone Redis-server via en SSL-forbindelse
  • redis-stik - en standalone Redis-server via et Unix-domænesokkel
  • redis-sentinel - en Redis Sentinel-server

Redis-databaseforekomsten kan angives som en del af URL-stien eller som en yderligere parameter. Hvis begge leveres, har parameteren højere prioritet.

I eksemplet ovenfor bruger vi en Snor repræsentation. Salat har også en RedisURI klasse til bygningstilslutninger. Det tilbyder 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 lighed med Jedis giver salat et komplet Redis-kommandosæt i form af metoder.

Salat implementerer imidlertid både synkron og asynkron version. Vi ser kort på den synkrone version og bruger derefter den asynkrone implementering i resten af ​​selvstudiet.

Når vi har oprettet en forbindelse, bruger vi den til at oprette et kommandosæt:

RedisCommands syncCommands = connection.sync (); 

Nu har vi en intuitiv grænseflade til kommunikation med Redis.

Vi kan indstille og få Strengværdier:

syncCommands.set ("nøgle", "Hej, Redis!"); Strengværdi = syncommands.get (“nøgle”); 

Vi kan arbejde med hashes:

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

Vi dækker flere Redis senere i artiklen.

Salat-synkron API bruger den asynkrone API. Blokering udføres for os på kommandoniveau. Dette betyder, at mere end en klient kan dele en synkron forbindelse.

4.4. Asynkrone kommandoer

Lad os se på de asynkrone kommandoer:

RedisAsyncCommands asyncCommands = forbindelse.async (); 

Vi henter et sæt af RedisAsyncCommands fra forbindelsen, svarende til hvordan vi hentede det synkrone sæt. Disse kommandoer returnerer a RedisFuture (hvilket er en Fuldført internt):

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

En guide til at arbejde med en Fuldført kan findes her.

4.5. Reaktiv API

Lad os endelig se, hvordan vi arbejder med ikke-blokerende reaktiv API:

RedisStringReactiveCommands reactiveCommands = connection.reactive (); 

Disse kommandoer returnerer resultater pakket ind i a Mono eller a Strøm fra Project Reactor.

En guide til at arbejde med Project Reactor kan findes her.

5. Redis datastrukturer

Vi kiggede kort på strenge og hashes ovenfor, lad os se på, hvordan Salat implementerer resten af ​​Redis 'datastrukturer. Som vi kunne forvente, har hver Redis-kommando en tilsvarende navngivet metode.

5.1. Lister

Lister er lister over Strenge med indsættelsesrækkefølgen bevaret. Værdier indsættes eller hentes fra begge ender:

asyncCommands.lpush ("opgaver", "første opgave"); asyncCommands.lpush ("opgaver", "secondTask"); RedisFuture redisFuture = asyncCommands.rpop ("opgaver"); Streng nextTask = redisFuture.get (); 

I dette eksempel næste opgave lige med "første opgave“. Lpush skubber værdier til hovedet på listen, og derefter rpop popper værdier fra slutningen af ​​listen.

Vi kan også pope elementer fra den anden ende:

asyncCommands.del ("opgaver"); asyncCommands.lpush ("opgaver", "første opgave"); asyncCommands.lpush ("opgaver", "secondTask"); redisFuture = asyncCommands.lpop ("opgaver"); Streng nextTask = redisFuture.get (); 

Vi starter det andet eksempel med at fjerne listen med del. Derefter indsætter vi de samme værdier igen, men vi bruger lpop for at poppe værdierne fra hovedet på listen, så næste opgave holder “secondTask”Tekst.

5.2. Sæt

Redis-sæt er uordnede samlinger af Strenge svarer til Java Sæt; der er ingen duplikatelementer:

asyncCommands.sadd ("kæledyr", "hund"); asyncCommands.sadd ("kæledyr", "kat"); asyncCommands.sadd ("kæledyr", "kat"); RedisFuture pets = asyncCommands.smembers ("kaldenavne"); RedisFuture findes = asyncCommands.sismember ("kæledyr", "hund"); 

Når vi henter Redis-indstillingen som en Sæt, størrelsen er to, da duplikatet "kat" blev ignoreret. Når vi spørger til Redis for eksistensen af "hund" med sismember, svaret er rigtigt.

5.3. Hashes

Vi kiggede kort på et eksempel på hash tidligere. De er en hurtig forklaring værd.

Redis Hashes er optegnelser med Snor felter og værdier. Hver post har også en nøgle i det primære indeks:

asyncCommands.hset ("recordName", "FirstName", "John"); asyncCommands.hset ("recordName", "LastName", "Smith"); RedisFuture sidste navn = syncCommands.hget ("recordName", "LastName"); RedisFuture record = syncCommands.hgetall ("recordName"); 

Vi bruger hset for at føje felter til hashen, videregive navnet på hashen, navnet på feltet og en værdi.

Derefter henter vi en individuel værdi med hget, navnet på posten og feltet. Endelig henter vi hele posten som en hash med hgetall.

5.4. Sorterede sæt

Sorterede sæt indeholder værdier og en rang, som de sorteres efter. Rangen er 64-bit floating point-værdi.

Elementer tilføjes med en rang og hentes i et interval:

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

Det andet argument til zadd er en rang. Vi henter et interval efter rang med zrange for stigende rækkefølge og zrevrange til nedstigning.

Vi tilføjede “nul”Med en rang på 4, så det vises i slutningen af værdier Fremad og i begyndelsen af værdier Omvendt.

6. Transaktioner

Transaktioner tillader udførelse af et sæt kommandoer i et enkelt atomtrin. Disse kommandoer udføres garanteret i rækkefølge og udelukkende. Kommandoer fra en anden bruger udføres først, før transaktionen er afsluttet.

Enten udføres alle kommandoer, eller ingen af ​​dem. Redis udfører ikke en tilbageførsel, hvis en af ​​dem fejler. Enkelt gang udføre () kaldes, udføres alle kommandoer i den angivne rækkefølge.

Lad os 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); 

Opkaldet til multi starter transaktionen. Når en transaktion startes, udføres de efterfølgende kommandoer først udføre () Hedder.

I synkron tilstand vender kommandoerne tilbage nul. I asynkron tilstand vender kommandoerne tilbage RedisFuture . Exec returnerer a Transaktionsresultat som indeholder en liste over svar.

Siden den RedisFutures modtager også deres resultater, asynkrone API-klienter modtager transaktionsresultatet to steder.

7. Batching

Under normale forhold udfører Salat kommandoer, så snart de kaldes op af en API-klient.

Dette er, hvad de fleste normale applikationer ønsker, især hvis de er afhængige af at modtage kommandoresultater serielt.

Denne adfærd er dog ikke effektiv, hvis applikationer ikke har brug for resultater med det samme, eller hvis store mængder data uploades samlet.

Asynkrone applikationer kan tilsidesætte denne adfærd:

commands.setAutoFlushCommands (false); Liste futures = ny ArrayList (); for (int i = 0; i <iterationer; 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 indstillet til falsk, skal applikationen ringe flushCommands manuelt. I dette eksempel stod vi flere i kø sæt kommando og skyllede derefter kanalen. Afvente alt venter på alle de RedisFutures at færdiggøre.

Denne tilstand indstilles pr. Tilslutningsbasis og påvirker alle tråde, der bruger forbindelsen. Denne funktion gælder ikke for synkrone kommandoer.

8. Udgiv / abonner

Redis tilbyder et simpelt publicerings- / abonnementsmeddelelsessystem. Abonnenter bruger meddelelser fra kanaler med abonnere kommando. Beskeder er ikke vedvarende; de leveres kun til brugere, når de abonnerer på en kanal.

Redis bruger pub / sub-systemet til meddelelser om Redis-datasættet, hvilket giver klienter mulighed for at modtage begivenheder om nøgler, der indstilles, slettes, udløber osv.

Se dokumentationen her for flere detaljer.

8.1. Abonnent

EN RedisPubSubListener modtager pub / underbeskeder. Denne grænseflade definerer flere metoder, men vi viser bare metoden til modtagelse af beskeder her:

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

Vi bruger RedisClient for at forbinde en pub / underkanal og installere lytteren:

StatefulRedisPubSubConnection-forbindelse = client.connectPubSub (); connection.addListener (ny lytter ()) RedisPubSubAsyncCommands async = connection.async (); async.subscribe ("kanal"); 

Når en lytter er installeret, henter vi et sæt af RedisPubSubAsyncCommands og abonner på en kanal.

8.2. Forlægger

Udgivelse er bare et spørgsmål om at forbinde en Pub / Sub-kanal og hente kommandoerne:

StatefulRedisPubSubConnection-forbindelse = client.connectPubSub (); RedisPubSubAsyncCommands async = forbindelse.async (); async.publish ("kanal", "Hej, Redis!"); 

Udgivelse kræver en kanal og en besked.

8.3. Reaktive abonnementer

Salat tilbyder også en reaktiv grænseflade til at abonnere på pub / undermeddelelser:

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

Det Strøm returneret af observer kanaler modtager beskeder til alle kanaler, men da dette er en stream, er det let at foretage filtrering.

9. Høj tilgængelighed

Redis tilbyder flere muligheder for høj tilgængelighed og skalerbarhed. Komplet forståelse kræver kendskab til Redis-serverkonfigurationer, men vi gennemgår en kort oversigt over, hvordan Salat understøtter dem.

9.1. Master / Slave

Redis-servere replikerer sig selv i en master / slave-konfiguration. Masterserveren sender slaven en strøm af kommandoer, der replikerer mastercachen til slaven. Redis understøtter ikke tovejs replikering, så slaver er skrivebeskyttede.

Salat kan oprette forbindelse til Master / Slave-systemer, spørge dem om topologien og derefter vælge slaver til læsningsoperationer, hvilket kan forbedre kapaciteten:

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

9.2. vagtpost

Redis Sentinel overvåger master- og slaveforekomster og orkestrerer failover til slaver i tilfælde af en master failover.

Salat kan oprette forbindelse til Sentinel, bruge den til at finde adressen på den aktuelle master og derefter returnere en forbindelse til den.

For at gøre dette bygger vi en anden RedisURI og forbinde vores RedisClient med det:

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

Vi byggede URI med værtsnavnet (eller adressen) på den første Sentinel og et klyngenavn efterfulgt af en anden sentinel-adresse. Når vi opretter forbindelse til Sentinel, spørger salat det om topologien og returnerer en forbindelse til den aktuelle masterserver for os.

Den komplette dokumentation er tilgængelig her.

9.3. Klynger

Redis Cluster bruger en distribueret konfiguration til at give høj tilgængelighed og høj kapacitet.

Klynger splinter nøgler over op til 1000 noder, derfor er transaktioner ikke tilgængelige i en klynge:

RedisURI redisUri = RedisURI.Builder.redis ("localhost"). MedPassword ("godkendelse"). Build (); RedisClusterClient clusterClient = RedisClusterClient .create (rediUri); StatefulRedisClusterConnection forbindelse = clusterClient.connect (); RedisAdvancedClusterCommands syncCommands = forbindelse .sync (); 

RedisAdvancedClusterCommands holder det sæt Redis-kommandoer, der understøttes af klyngen, og dirigerer dem til den instans, der indeholder nøglen.

En komplet specifikation er tilgængelig her.

10. Konklusion

I denne vejledning så vi på, hvordan man bruger salat til at oprette forbindelse til og forespørgsel på en Redis-server indefra vores applikation.

Salat understøtter det komplette sæt Redis-funktioner med bonus på en fuldstændig trådsikker asynkron grænseflade. Det gør også omfattende brug af Java 8'er FuldførelseStage interface til at give applikationer en finkornet kontrol over, hvordan de modtager data.

Kodeprøver kan som altid findes på GitHub.


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