Uvod u salatu - Java Redis klijent

1. Pregled

Ovaj je članak uvod u Lettuce, klijent Redis Java.

Redis je memorija ključa / vrijednosti u memoriji koja se može koristiti kao posrednik baze podataka, predmemorije ili poruka. Podaci se dodaju, ispituju, mijenjaju i brišu naredbama koje djeluju na tipke u Redisovoj strukturi podataka u memoriji.

Zelena salata podržava i sinkronu i asinkronu komunikaciju korištenja kompletnog API-ja Redis, uključujući njegove podatkovne strukture, pub / sub poruke i veze poslužitelja visoke dostupnosti.

2. Zašto zelena salata?

Jedide smo obradili u jednom od prethodnih postova. Po čemu je salata drugačija?

Najznačajnija razlika je njegova asinkrona podrška putem Jave 8 CompletionStage sučelje i podrška za reaktivne tokove. Kao što ćemo vidjeti u nastavku, Salata nudi prirodno sučelje za izradu asinkronih zahtjeva s poslužitelja baze podataka Redis i za stvaranje streamova.

Također koristi Netty za komunikaciju s poslužiteljem. To čini "teži" API, ali i čini ga prikladnijim za dijeljenje veze s više od jedne niti.

3. Postavljanje

3.1. Ovisnost

Počnimo s proglašenjem jedine ovisnosti koja će nam trebati u pom.xml:

 io.lattuce salata-core 5.0.1.OBUSTAVLJANJE 

Najnoviju verziju knjižnice možete provjeriti na spremištu Github ili na Maven Central.

3.2. Instalacija Redis

Morat ćemo instalirati i pokrenuti barem jedan primjerak Redisa, dva ako želimo testirati način grupiranja ili sentinel način (iako sentinel način rada zahtijeva tri poslužitelja za ispravno funkcioniranje.) Za ovaj članak koristimo 4.0.x - trenutno najnovija stabilna verzija.

Više informacija o početku rada s Redisom možete pronaći ovdje, uključujući preuzimanja za Linux i MacOS.

Redis službeno ne podržava Windows, ali ovdje postoji priključak poslužitelja. Redis možemo pokrenuti i u Dockeru, što je bolja alternativa za Windows 10 i brz način pokretanja i pokretanja.

4. Veze

4.1. Povezivanje s poslužiteljem

Povezivanje s Redisom sastoji se od četiri koraka:

  1. Stvaranje Redis URI-ja
  2. Korištenje URI-a za povezivanje s a RedisClient
  3. Otvaranje Redis veze
  4. Generiranje skupa RedisCommands

Pogledajmo implementaciju:

RedisClient redisClient = RedisClient .create ("redis: // [zaštićen e-poštom]: 6379 /"); StatefulRedisConnection veza = redisClient.connect ();

A StatefulRedisConnection kako to zvuči; veza sigurna u nit na Redis poslužitelj koji će održavati vezu s poslužiteljem i po potrebi se ponovno povezati. Nakon što uspostavimo vezu, možemo je koristiti za izvršavanje Redis naredbi bilo sinkrono ili asinkrono.

RedisClient koristi značajne resurse sustava jer posjeduje Netty resurse za komunikaciju s Redis poslužiteljem. Aplikacije koje zahtijevaju višestruke veze trebaju koristiti jednu RedisClient.

4.2. Redis URI-i

Mi stvaramo RedisClient prosljeđivanjem URI-ja statičkoj tvorničkoj metodi.

Zelena salata koristi prilagođenu sintaksu za Redis URI-je. Ovo je shema:

redis: // [[e-pošta zaštićena]] host [: port] [/ baza podataka] [? [timeout = timeout [d | h | m | s | ms | us | ns]] [& _database = baza podataka_]] 

Postoje četiri URI sheme:

  • redis - samostalni Redisov poslužitelj
  • rediss - samostalni Redis poslužitelj putem SSL veze
  • redis-utičnica - samostalni Redis poslužitelj putem utičnice Unix domene
  • redis-sentinel - poslužitelj Redis Sentinel

Primjer baze podataka Redis može se navesti kao dio putanje URL-a ili kao dodatni parametar. Ako su isporučene obje, parametar ima veći prioritet.

U gornjem primjeru koristimo a Niz zastupanje. Zelena salata također ima RedisURI razred za izgradnju veza. Nudi Graditelj uzorak:

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

I konstruktor:

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

4.3. Sinkrone naredbe

Slično jedima, i salata nudi cjeloviti skup naredbi Redis u obliku metoda.

Međutim, Salata implementira i sinkrone i asinkrone verzije. Kratko ćemo pogledati sinkronu verziju, a zatim ćemo koristiti asinkronu implementaciju za ostatak vodiča.

Nakon što stvorimo vezu, koristimo je za stvaranje skupa naredbi:

RedisCommands syncCommands = connection.sync (); 

Sada imamo intuitivno sučelje za komunikaciju s Redisom.

Možemo postaviti i dobiti Vrijednosti niza:

syncCommands.set ("key", "Hello, Redis!"); Vrijednost niza = syncommands.get ("ključ"); 

Možemo raditi s hešovima:

syncCommands.hset ("recordName", "FirstName", "John"); syncCommands.hset ("recordName", "LastName", "Smith"); Karta zapis = syncCommands.hgetall ("recordName"); 

Više Redisa pokriti ćemo kasnije u članku.

Sinkroni API API salate koristi asinkroni API. Blokiranje se vrši za nas na zapovjednoj razini. To znači da više od jednog klijenta može dijeliti sinkronu vezu.

4.4. Asinkrone naredbe

Pogledajmo asinkrone naredbe:

RedisAsyncCommands asyncCommands = connection.async (); 

Dohvaćamo skup RedisAsyncCommands iz veze, slično onome kako smo dohvatili sinkroni skup. Te naredbe vraćaju a RedisFuture (što je a CompletableFuture interno):

RedisFuture rezultat = asyncCommands.get ("ključ"); 

Vodič za rad s a CompletableFuture možete pronaći ovdje.

4.5. Reactive API

Na kraju, pogledajmo kako raditi s neblokirajućim reaktivnim API-jem:

RedisStringReactiveCommands reactiveCommands = connection.reactive (); 

Te naredbe vraćaju rezultate umotane u Mono ili a Fluks iz Project Reactor-a.

Vodič za rad s Project Reactor-om možete pronaći ovdje.

5. Redisove strukture podataka

Gore smo kratko pregledali nizove i hashove, pogledajmo kako Lettuce implementira ostatak Redisovih struktura podataka. Kao što bismo i očekivali, svaka naredba Redis ima slično nazvanu metodu.

5.1. Popisi

Popisi su popisi Žice uz očuvan redoslijed umetanja. Vrijednosti su umetnute ili dohvaćene s bilo kojeg kraja:

asyncCommands.lpush ("zadaci", "prvi zadatak"); asyncCommands.lpush ("zadaci", "druga zadaća"); RedisFuture redisFuture = asyncCommands.rpop ("zadaci"); Niz nextTask = redisFuture.get (); 

U ovom primjeru, nextTask jednako "firstTask“. Lpush gura vrijednosti u glavu popisa, a zatim rpop iskače vrijednosti s kraja popisa.

Možemo pojaviti i elemente s drugog kraja:

asyncCommands.del ("zadaci"); asyncCommands.lpush ("zadaci", "prvi zadatak"); asyncCommands.lpush ("zadaci", "druga zadaća"); redisFuture = asyncCommands.lpop ("zadaci"); Niz nextTask = redisFuture.get (); 

Drugi primjer započinjemo uklanjanjem popisa sa del. Zatim ponovno umetnemo iste vrijednosti, ali koristimo lpop za iskakanje vrijednosti s glave popisa, pa nextTask drži “secondTask”Tekst.

5.2. Kompleti

Redis Sets su neuređene kolekcije Žice slično Javi Kompleti; nema dupliciranih elemenata:

asyncCommands.sadd ("kućni ljubimci", "pas"); asyncCommands.sadd ("kućni ljubimci", "mačka"); asyncCommands.sadd ("kućni ljubimci", "mačka"); RedisFuture kućni ljubimci = asyncCommands.smembers ("nadimci"); RedisFuture postoji = asyncCommands.sismember ("kućni ljubimci", "pas"); 

Kad dohvatimo Redis postavljen kao Postavi, veličina je dvije, jer je duplikat "mačka" bio ignoriran. Kada upitamo Redis za postojanje "pas" s sismember, odgovor je pravi.

5.3. Hashevi

Prije smo ukratko pogledali primjer hashiranja. Vrijedi ih brzo objasniti.

Redis hashes su ploče s Niz polja i vrijednosti. Svaki zapis također ima ključ u primarnom indeksu:

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

Koristimo hset za dodavanje polja u hash, unošenjem imena hasha, imena polja i vrijednosti.

Zatim dohvaćamo pojedinačnu vrijednost pomoću hget, naziv zapisa i polje. Konačno, čitav zapis dohvaćamo kao hash hgetall.

5.4. Poredani skupovi

Sortirani skupovi sadrže vrijednosti i rang po kojem su razvrstani. Poredak je 64-bitna vrijednost s pomičnim zarezom.

Stavke se dodaju s rangom i dohvaćaju u rasponu:

asyncCommands.zadd ("sortirani skup", 1, "jedan"); asyncCommands.zadd ("sortirani skup", 4, "nula"); asyncCommands.zadd ("sortirani skup", 2, "dva"); RedisFuture valuesForward = asyncCommands.zrange (ključ, 0, 3); RedisFuture valuesReverse = asyncCommands.zrevrange (ključ, 0, 3); 

Drugi argument za zadd je čin. Dohvaćamo raspon prema rangu s zrange za uzlazni poredak i zrevrange za silazak.

Dodali smo "nula”S rangom 4, pa će se pojaviti na kraju vrijednostiNaprijed i na početku vrijednostiReverse.

6. Transakcije

Transakcije omogućuju izvršavanje niza naredbi u jednom atomskom koraku. Ove se naredbe garantirano izvršavaju redom i isključivo. Naredbe drugog korisnika neće se izvršavati dok transakcija ne završi.

Ili se izvršavaju sve naredbe ili niti jedna od njih nije. Redis neće izvršiti povrat, ako jedan od njih ne uspije. Jednom izvršiti () sve naredbe izvršavaju se navedenim redoslijedom.

Pogledajmo primjer:

asyncCommands.multi (); RedisFuture rezultat1 = asyncCommands.set ("key1", "value1"); RedisFuture rezultat2 = asyncCommands.set ("key2", "value2"); RedisFuture rezultat3 = asyncCommands.set ("key3", "value3"); RedisFuture execResult = asyncCommands.exec (); TransactionResultactionResult = execResult.get (); Niz firstResult =actionResult.get (0); Niz secondResult =actionResult.get (0); Niz thirdResult =actionResult.get (0); 

Poziv na multi započinje transakciju. Kada se transakcija započne, naredne naredbe izvršavaju se tek izvršiti () Zove se.

U sinkronom načinu naredbe se vraćaju null. U asinkronom načinu naredbe se vraćaju RedisFuture . Izv vraća a Rezultat transakcije koja sadrži popis odgovora.

Budući da je RedisFutures također primaju svoje rezultate, asinkroni API klijenti primaju rezultat transakcije na dva mjesta.

7. Doziranje

U normalnim uvjetima, Salata izvršava naredbe čim ih API klijent pozove.

To je ono što većina normalnih aplikacija želi, posebno ako se oslanjaju na serijsko primanje rezultata naredbi.

Međutim, ovo ponašanje nije učinkovito ako aplikacije ne trebaju rezultate odmah ili se velike količine podataka prenose skupno.

Asinkrone aplikacije mogu nadjačati ovo ponašanje:

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

S postavljenim setAutoFlushCommands na lažno, aplikacija mora nazvati isprati naredbe ručno. U ovom smo primjeru stavili u red čekanja postavljen naredbu, a zatim isprao kanal. Čekaj sve čeka sve RedisFutures dovršiti.

Ovo se stanje postavlja na osnovu veze i utječe na sve niti koje koriste vezu. Ova značajka nije primjenjiva na sinkrone naredbe.

8. Objavi / pretplati se

Redis nudi jednostavan sustav za objavljivanje / pretplatu na razmjenu poruka. Pretplatnici troše poruke s kanala s pretplatite se naredba. Poruke se ne zadržavaju; isporučuju se korisnicima samo kada su pretplaćeni na kanal.

Redis koristi sustav pub / sub za obavijesti o Redisovom skupu podataka, pružajući klijentima mogućnost primanja događaja o postavljanju, brisanju, isteku ključeva itd., Itd.

Pogledajte dokumentaciju ovdje za više detalja.

8.1. Pretplatnik

A RedisPubSubListener prima pub / sub poruke. Ovo sučelje definira nekoliko metoda, ali ovdje ćemo samo prikazati način primanja poruka:

slušatelj javne klase implementira RedisPubSubListener {@Override javna void poruka (kanal niza, niz poruka) {log.debug ("Dobio {}} na kanalu {}", poruka, kanal); poruka = ​​novi niz (s2); }} 

Koristimo RedisClient da biste povezali pub / podkanal i instalirali slušatelj:

StatefulRedisPubSubConnection veza = client.connectPubSub (); connection.addListener (novi slušalac ()) RedisPubSubAsyncCommands async = connection.async (); async.subscribe ("kanal"); 

S instaliranim slušateljem dohvaćamo skup RedisPubSubAsyncCommands i pretplatite se na kanal.

8.2. Izdavač

Objavljivanje je samo pitanje povezivanja Pub / Sub kanala i dohvaćanja naredbi:

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

Za objavljivanje su potrebni kanal i poruka.

8.3. Reaktivne pretplate

Zelena salata također nudi reaktivno sučelje za pretplatu na pub / sub poruke:

StatefulRedisPubSubConnection veza = klijent .connectPubSub (); RedisPubSubAsyncCommands reaktivan = veza .reactive (); reactive.observeChannels (). pretplatite se (poruka -> {log.debug ("Dobio {} na kanalu {}", poruka, kanal); poruka = ​​novi niz (s2);}); reactive.subscribe ("channel"). subscribe (); 

The Fluks vratio do promatratiKanale prima poruke za sve kanale, ali budući da je ovo stream, filtriranje je jednostavno izvršiti.

9. Velika dostupnost

Redis nudi nekoliko mogućnosti za visoku dostupnost i skalabilnost. Potpuno razumijevanje zahtijeva poznavanje konfiguracija poslužitelja Redis, no proći ćemo kroz kratki pregled načina na koji ih Salata podržava.

9.1. Gospodar / rob

Redis poslužitelji se repliciraju u glavnoj / podređenoj konfiguraciji. Glavni poslužitelj šalje slave podređeni tok naredbi koje repliciraju glavnu predmemoriju na slave. Redis ne podržava dvosmjernu replikaciju, pa su robovi samo za čitanje.

Salata se može povezati s glavnim / podređenim sustavima, pitati ih za topologiju, a zatim odabrati podređene uređaje za operacije čitanja, što može poboljšati propusnost:

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

9.2. Sentinel

Redis Sentinel nadgleda glavne i podređene slučajeve i orkestrira preusmjeravanje na robove u slučaju glavnog preusmjeravanja.

Salata se može povezati sa Sentinelom, pomoću nje otkriti adresu trenutnog gospodara, a zatim vratiti vezu na nju.

Da bismo to učinili, gradimo drugačiji RedisURI i povezati naše RedisClient s tim:

RedisURI redisUri = RedisURI.Builder .sentinel ("sentinelhost1", "ime klastera") .withSentinel ("sentinelhost2"). Build (); RedisClient klijent = novi RedisClient (redisUri); RedisConnection veza = client.connect (); 

Izgradili smo URI s imenom hosta (ili adresom) prvog Sentinela i imenom klastera, nakon čega je slijedila druga sentinel adresa. Kada se povežemo sa Sentinelom, Zelena salata postavlja upit o topologiji i vraća nam vezu na trenutni glavni poslužitelj.

Kompletna dokumentacija dostupna je ovdje.

9.3. Klasteri

Redis Cluster koristi distribuiranu konfiguraciju kako bi osigurao visoku dostupnost i veliku propusnost.

Ključevi krhotina klastera na do 1000 čvorova, stoga transakcije nisu dostupne u klasteru:

RedisURI redisUri = RedisURI.Builder.redis ("localhost") .withPassword ("autentifikacija"). Build (); RedisClusterClient clusterClient = RedisClusterClient .create (rediUri); StatefulRedisClusterConnection veza = clusterClient.connect (); RedisAdvancedClusterCommands syncCommands = veza .sync (); 

RedisAdvancedClusterCommands sadrži skup naredbi Redis podržanih klasterom, usmjeravajući ih na instancu koja sadrži ključ.

Kompletna specifikacija dostupna je ovdje.

10. Zaključak

U ovom smo uputstvu pogledali kako koristiti salatu za povezivanje i postavljanje upita za Redis poslužitelj iz naše aplikacije.

Zelena salata podržava čitav niz Redisovih značajki, uz bonus potpuno nitnog asinkronog sučelja. Također se široko koristi Java 8-ima CompletionStage sučelje za pružanje aplikacijama precizne kontrole nad načinom primanja podataka.

Uzorke koda, kao i uvijek, možete pronaći na GitHubu.


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