Úvod do šalátu - klient Java Redis

1. Prehľad

Tento článok je úvodom do šalátu, klienta Redis Java.

Redis je úložisko kľúčov a hodnôt v pamäti, ktoré možno použiť ako databázu, medzipamäť alebo sprostredkovateľa správ. Dáta sú pridávané, dopytované, upravené a mazané pomocou príkazov, ktoré fungujú na klávesoch v dátovej štruktúre Redis v pamäti.

Šalát podporuje synchrónnu aj asynchrónnu komunikáciu s využitím kompletného rozhrania Redis API vrátane jeho dátových štruktúr, správy pub / sub a pripojenia servera s vysokou dostupnosťou.

2. Prečo hlávkový šalát?

Jedisom sme sa venovali v jednom z predchádzajúcich príspevkov. V čom je šalát iný?

Najvýznamnejším rozdielom je jeho asynchrónna podpora prostredníctvom Java 8 DokončenieStage rozhranie a podpora pre Reactive Streams. Ako uvidíme ďalej, Lettuce ponúka prirodzené rozhranie na vytváranie asynchrónnych požiadaviek z databázového servera Redis a na vytváranie prúdov.

Ďalej používa Netty na komunikáciu so serverom. Toto umožňuje „ťažšie“ API, ale tiež sa lepšie hodí na zdieľanie spojenia s viac ako jedným vláknom.

3. Inštalácia

3.1. Závislosť

Začnime vyhlásením jedinej závislosti, ktorú budeme v pom.xml:

 io.lettuťový šalát-jadro 5.0.1. UVOĽNENIE 

Najnovšiu verziu knižnice môžete skontrolovať v úložisku Github alebo Maven Central.

3.2. Inštalácia Redis

Budeme musieť nainštalovať a spustiť aspoň jednu inštanciu Redis, dve, ak chceme otestovať režim klastrovania alebo sentinel (aj keď režim sentinel vyžaduje pre správnu funkciu tri servery.) Pre tento článok používame 4.0.x - najnovšiu stabilnú verziu.

Viac informácií o tom, ako začať s Redisom, nájdete tu, vrátane súborov na stiahnutie pre Linux a MacOS.

Redis oficiálne nepodporuje Windows, ale je tu port servera. Redis môžeme spustiť aj v Dockri, čo je lepšia alternatíva pre Windows 10 a rýchly spôsob uvedenia do prevádzky.

4. Pripojenia

4.1. Pripojenie k serveru

Pripojenie k Redis pozostáva zo štyroch krokov:

  1. Vytvorenie Redis URI
  2. Používanie URI na pripojenie k a RedisClient
  3. Otvorí sa pripojenie Redis
  4. Generuje sa sada RedisCommands

Pozrime sa na implementáciu:

RedisClient redisClient = RedisClient .create ("redis: // [chránený e-mailom]: 6379 /"); StatefulRedisConnection connection = redisClient.connect ();

A StatefulRedisConnection ako to znie; vlákno bezpečné pripojenie k serveru Redis, ktorý zachová jeho pripojenie k serveru a v prípade potreby sa znova pripojí. Keď už máme pripojenie, môžeme ho použiť na vykonávanie príkazov Redis buď synchrónne alebo asynchrónne.

RedisClient využíva značné systémové prostriedky, pretože drží prostriedky Netty na komunikáciu so serverom Redis. Aplikácie vyžadujúce viac pripojení by mali používať jediné RedisClient.

4.2. Redis URI

Vytvárame a RedisClient odovzdaním URI statickej továrenskej metóde.

Šalát využíva vlastnú syntax pre identifikátory URI Redis. Toto je schéma:

redis: // [[chránený e-mailom]] hostiteľ [: port] [/ databáza] [? [časový limit = časový limit [d | h | m | s | ms | nás | ns]] [& _database = databáza_]] 

Existujú štyri schémy URI:

  • redis Samostatný server Redis
  • rediss - samostatný server Redis prostredníctvom pripojenia SSL
  • Redis-zásuvka - samostatný server Redis cez soket domény Unix
  • redis-sentinel - server Redis Sentinel

Inštanciu databázy Redis možno určiť ako súčasť cesty URL alebo ako ďalší parameter. Ak sú dodané obidve, parameter má vyššiu prednosť.

Vo vyššie uvedenom príklade používame a String zastúpenie. Šalát má tiež a RedisURI triedy pre budovanie prípojok. Ponúka Staviteľ vzor:

RedisURI.Builder .redis ("localhost", 6379) .auth ("heslo") .databáza (1) .build (); 

A konštruktér:

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

4.3. Synchrónne príkazy

Podobne ako Jedis, aj Lettuce poskytuje kompletnú sadu príkazov Redis vo forme metód.

Šalát však implementuje synchrónnu aj asynchrónnu verziu. Krátko sa pozrieme na synchrónnu verziu a po zvyšok tohto tutoriálu použijeme asynchrónnu implementáciu.

Po vytvorení spojenia ho použijeme na vytvorenie množiny príkazov:

RedisCommands syncCommands = connection.sync (); 

Teraz máme intuitívne rozhranie pre komunikáciu s Redis.

Môžeme nastaviť a dostať Hodnoty reťazca:

syncCommands.set ("key", "Hello, Redis!"); Reťazcová hodnota = syncommands.get („kľúč“); 

Môžeme pracovať s hashmi:

syncCommands.hset ("názov záznamu", "meno", "John"); syncCommands.hset ("recordName", "LastName", "Smith"); Záznam na mape = syncCommands.hgetall ("názov záznamu"); 

Viac Redisu sa budeme venovať neskôr v článku.

Synchrónne API hlávkového šalátu používa asynchrónne API. Blokovanie sa robí za nás na príkazovej úrovni. To znamená, že viac ako jeden klient môže zdieľať synchrónne pripojenie.

4.4. Asynchrónne príkazy

Pozrime sa na asynchrónne príkazy:

RedisAsyncCommands asyncCommands = connection.async (); 

Získame súbor RedisAsyncCommands zo spojenia, podobne ako sme načítali synchrónnu množinu. Tieto príkazy vrátia a RedisFuture (čo je a CompletableFuture interne):

RedisFuture result = asyncCommands.get ("kľúč"); 

Sprievodca prácou s a CompletableFuture nájdete tu.

4.5. Reaktívne API

Na záver sa pozrime, ako pracovať s neblokujúcim reaktívnym rozhraním API:

RedisStringReactiveCommands reactiveCommands = connection.reactive (); 

Tieto príkazy vrátia výsledky zabalené do a Mono alebo a Flux z Project Reactor.

Sprievodcu prácou s Project Reactor nájdete tu.

5. Redis dátové štruktúry

Krátko sme sa pozreli na reťazce a hašovanie vyššie, poďme sa pozrieť na to, ako Lettuce implementuje zvyšok dátových štruktúr Redis. Ako by sme čakali, každý príkaz Redis má metódu s rovnakým názvom.

5.1. Zoznamy

Zoznamy sú zoznamy Struny so zachovaným poradím vloženia. Hodnoty sa vkladajú alebo načítajú z oboch koncov:

asyncCommands.lpush ("tasks", "firstTask"); asyncCommands.lpush ("tasks", "secondTask"); RedisFuture redisFuture = asyncCommands.rpop ("úlohy"); Reťazec nextTask = redisFuture.get (); 

V tomto príklade nextTask rovná sa „firstTask“. Lpush posúva hodnoty na čelo zoznamu a potom rpop zobrazí hodnoty od konca zoznamu.

Môžeme tiež vysunúť prvky z druhého konca:

asyncCommands.del ("úlohy"); asyncCommands.lpush ("tasks", "firstTask"); asyncCommands.lpush ("tasks", "secondTask"); redisFuture = asyncCommands.lpop ("úlohy"); Reťazec nextTask = redisFuture.get (); 

Druhý príklad začneme odstránením zoznamu pomocou del. Potom opäť vložíme rovnaké hodnoty, ale použijeme lpop na vyskakovanie hodnôt z hlavičky zoznamu, teda na nextTask drží “secondTask”Text.

5.2. Sady

Sady Redis sú neusporiadané zbierky Struny podobne ako Java Sady; neexistujú žiadne duplicitné prvky:

asyncCommands.sadd ("domáce zvieratá", "pes"); asyncCommands.sadd ("domáce zvieratá", "mačka"); asyncCommands.sadd ("domáce zvieratá", "mačka"); RedisFuture domáce zvieratá = asyncCommands.smembers ("prezývky"); RedisFuture existuje = asyncCommands.sismember ("domáce zvieratá", "pes"); 

Keď načítame súpravu Redis ako a Nastaviť, veľkosť je dva, pretože duplikát „Mačka“ bol ignorovaný. Keď sa pýtame Redis na existenciu "pes" s sismember, odpoveď je pravda.

5.3. Hashes

Krátko sme sa pozreli na príklad hashov predtým. Stojí za rýchle vysvetlenie.

Redis Hashes sú záznamy s String polia a hodnoty. Každý záznam má tiež kľúč v primárnom indexe:

asyncCommands.hset ("recordName", "FirstName", "John"); asyncCommands.hset ("recordName", "LastName", "Smith"); RedisFuture priezvisko = syncCommands.hget ("názov záznamu", "priezvisko"); RedisFuture záznam = syncCommands.hgetall ("názov záznamu"); 

Používame hset na pridanie polí do hash, zadanie názvu hash, názvu poľa a hodnoty.

Potom získame individuálnu hodnotu pomocou hget, názov záznamu a pole. Nakoniec načítame celý záznam ako hash s hgetall.

5.4. Zoradené sady

Zoradené množiny obsahujú hodnoty a poradie, podľa ktorého sú zoradené. Poradie je 64-bitová hodnota s pohyblivou rádovou čiarkou.

Položky sa pridávajú s hodnotením a vyhľadávajú sa v rozsahu:

asyncCommands.zadd ("triedená sada", 1, "jedna"); asyncCommands.zadd ("triedená sada", 4, "nula"); asyncCommands.zadd ("triedená sada", 2, "dve"); RedisFuture valuesForward = asyncCommands.zrange (kľúč, 0, 3); RedisFuture valuesReverse = asyncCommands.zrevrange (kľúč, 0, 3); 

Druhý argument k zadd je hodnosť. Načítame rozsah podľa poradia s zrange pre vzostupné poradie a zrevrange na zostup.

Pridali sme „nula”S hodnosťou 4, takže sa objaví na konci roka valuesForward a na začiatku hodnotyReverzné.

6. Transakcie

Transakcie umožňujú vykonávanie sady príkazov v jednom atómovom kroku. Zaručene sa tieto príkazy vykonajú v uvedenom poradí a výlučne. Príkazy od iného používateľa sa vykonajú až po dokončení transakcie.

Buď sa vykonajú všetky príkazy, alebo sa nevykonajú žiadne. Redis nevykoná vrátenie, ak jeden z nich zlyhá. Raz exec () sa volajú, všetky príkazy sa vykonávajú v uvedenom poradí.

Pozrime sa na príklad:

asyncCommands.multi (); RedisFuture result1 = asyncCommands.set ("kľúč1", "hodnota1"); RedisFuture result2 = asyncCommands.set ("key2", "value2"); RedisFuture result3 = asyncCommands.set ("key3", "value3"); RedisFuture execResult = asyncCommands.exec (); TransactionResult transactionResult = execResult.get (); Reťazec firstResult = transactionResult.get (0); Reťazec secondResult = transactionResult.get (0); Reťazec thirdResult = transactionResult.get (0); 

Výzva na multi spustí transakciu. Po spustení transakcie sa nasledujúce príkazy nevykonajú, kým exec () sa volá.

V synchrónnom režime sa príkazy vrátia nulový. V asynchrónnom režime sa príkazy vrátia RedisFuture . Exec vracia a TransactionResult ktorá obsahuje zoznam odpovedí.

Keďže RedisFutures tiež dostanú svoje výsledky, asynchrónni klienti API dostanú výsledok transakcie na dvoch miestach.

7. Dávkovanie

Za normálnych podmienok šalát vykoná príkazy hneď, ako ich zavolá klient API.

To chce väčšina bežných aplikácií, najmä ak sa spoliehajú na sériové prijímanie výsledkov príkazov.

Toto správanie však nie je efektívne, ak aplikácie nepotrebujú výsledky okamžite alebo ak sa hromadne nahráva veľké množstvo údajov.

Asynchrónne aplikácie môžu toto správanie prepísať:

commands.setAutoFlushCommands (false); Zoznam futures = nový 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 (nový RedisFuture [0])); 

S setAutoFlushCommands nastaveným na nepravdivé, aplikácia musí volať flushCommands ručne. V tomto príklade sme zaradili do radu viac nastaviť príkaz a potom prepláchol kanál. AwaitAll čaká na všetky RedisFutures dokončiť.

Tento stav je nastavený na jednotlivé pripojenie a ovplyvňuje všetky vlákna, ktoré používajú pripojenie. Táto funkcia nie je použiteľná pre synchrónne príkazy.

8. Publikovať / Prihlásiť sa na odber

Redis ponúka jednoduchý systém správ na publikovanie / prihlásenie na odber. Odberatelia konzumujú správy z kanálov pomocou prihlásiť sa na odber príkaz. Správy nie sú trvalé; doručujú sa používateľom iba vtedy, keď sú prihlásení na odber kanála.

Redis používa systém pub / sub na oznámenia o datasete Redis, vďaka čomu môžu klienti dostávať udalosti týkajúce sa nastavovania, mazania, platnosti kľúčov atď.

Ďalšie informácie nájdete v dokumentácii tu.

8.1. Predplatiteľ

A RedisPubSubListener prijíma správy / správy. Toto rozhranie definuje niekoľko metód, ale tu ukážeme iba spôsob prijímania správ:

public class Listener implementuje RedisPubSubListener {@Override public void message (String channel, String message) {log.debug ("Got {} on channel {}", message, channel); message = nový reťazec (s2); }} 

Používame RedisClient na pripojenie pub / sub kanálu a inštaláciu poslucháča:

StatefulRedisPubSubConnection pripojenie = client.connectPubSub (); connection.addListener (new Listener ()) RedisPubSubAsyncCommands async = connection.async (); async.subscribe ("kanál"); 

S nainštalovaným poslucháčom načítame množinu RedisPubSubAsyncCommands a prihlásiť sa na odber kanála.

8.2. Vydavateľ

Publikovanie je len otázkou pripojenia Pub / Sub kanála a načítania príkazov:

StatefulRedisPubSubConnection pripojenie = client.connectPubSub (); RedisPubSubAsyncCommands async = connection.async (); async.publish ("channel", "Hello, Redis!"); 

Zverejnenie vyžaduje kanál a správu.

8.3. Reaktívne predplatné

Salát tiež ponúka reaktívne rozhranie na prihlásenie sa k odberu pub / sub správ:

StatefulRedisPubSubConnection pripojenie = klient .connectPubSub (); RedisPubSubAsyncCommands reaktívne = pripojenie .reaktívne (); reactive.observeChannels (). subscribe (message -> {log.debug ("Got {} on channel {}", message, channel); message = new String (s2);}); reactive.subscribe ("kanál"). subscribe (); 

The Flux vrátil sa sledovať kanály prijíma správy pre všetky kanály, ale keďže ide o stream, filtrovanie je ľahké.

9. Vysoká dostupnosť

Redis ponúka niekoľko možností vysokej dostupnosti a škálovateľnosti. Úplné pochopenie vyžaduje znalosť konfigurácií servera Redis, prejdeme však krátkym prehľadom toho, ako ich podporuje služba Lettuce.

9.1. Pán / otrok

Servery Redis sa replikujú v konfigurácii typu master / slave. Hlavný server odošle slave prúd príkazov, ktoré replikujú hlavnú vyrovnávaciu pamäť slave. Redis nepodporuje obojsmernú replikáciu, takže otroci sú iba na čítanie.

Šalát sa môže pripojiť k systémom Master / Slave, dopytovať sa po ňom na topológiu a potom vyberať otrokov pre operácie čítania, čo môže zvýšiť priepustnosť:

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

9.2. Sentinel

Spoločnosť Redis Sentinel monitoruje inštancie pánov a otrokov a v prípade zlyhania majstra orchestruje zlyhania pre otrokov.

Šalát sa môže pripojiť k Sentinelu, použiť ho na zistenie adresy aktuálneho pána a potom k nemu vrátiť spojenie.

Aby sme to dosiahli, staviame inú RedisURI a spojiť naše RedisClient s tým:

RedisURI redisUri = RedisURI.Builder .sentinel ("sentinelhost1", "clustername") .wSSentinel ("sentinelhost2"). Build (); RedisClient klient = nový RedisClient (redisUri); RedisConnection connection = client.connect (); 

Vytvorili sme URI s názvom hostiteľa (alebo adresou) prvého Sentinelu a názvom klastra, za ktorým nasleduje druhá sentinel adresa. Keď sa pripojíme k Sentinelu, služba Lettuce sa jej opýta na topológiu a vráti nám pripojenie k aktuálnemu hlavnému serveru.

Kompletná dokumentácia je k dispozícii tu.

9.3. Klastre

Redis Cluster používa distribuovanú konfiguráciu na zabezpečenie vysokej dostupnosti a vysokej priepustnosti.

Klastre rozkladajú kľúče až na 1 000 uzloch, preto transakcie nie sú v klastri k dispozícii:

RedisURI redisUri = RedisURI.Builder.redis ("localhost") .withPassword ("autentifikácia"). Build (); RedisClusterClient clusterClient = RedisClusterClient .create (rediUri); StatefulRedisClusterConnection connection = clusterClient.connect (); RedisAdvancedClusterCommands syncCommands = pripojenie .sync (); 

RedisAdvancedClusterCommands uchováva množinu príkazov Redis podporovaných klastrom a smeruje ich do inštancie, ktorá obsahuje kľúč.

Kompletná špecifikácia je k dispozícii tu.

10. Záver

V tomto tutoriáli sme sa pozreli na to, ako používať službu Lettuce na pripojenie servera Redis a dopytovanie z neho v rámci našej aplikácie.

Salát podporuje kompletnú sadu funkcií Redis s bonusom asynchrónneho rozhrania úplne bezpečného pre vlákna. Taktiež rozsiahlo využíva Java 8 DokončenieStage rozhranie, ktoré dáva aplikáciám podrobnú kontrolu nad tým, ako prijímajú údaje.

Ukážky kódu, ako vždy, nájdete na GitHub.