Inleiding tot Jedis - de Java Redis-clientbibliotheek

1. Overzicht

Dit artikel is een inleiding tot Jedi's, een clientbibliotheek in Java voor Redis - de populaire datastructuuropslag in het geheugen die ook op schijf kan blijven staan. Het wordt aangestuurd door een keystore-gebaseerde datastructuur om gegevens te bewaren en kan worden gebruikt als database, cache, message broker, enz.

Eerst gaan we uitleggen in welke situaties Jedis nuttig is en waar het over gaat.

In de volgende paragrafen gaan we dieper in op de verschillende datastructuren en leggen we transacties, pipelining en de publish / subscribe-functie uit. We sluiten af ​​met pooling van verbindingen en Redis Cluster.

2. Waarom Jedi's?

Redis geeft de bekendste clientbibliotheken weer op hun officiële site. Er zijn meerdere alternatieven voor Jedi's, maar er zijn momenteel nog maar twee die hun aanbevelingsster, sla en Redisson waardig zijn.

Deze twee clients hebben enkele unieke functies, zoals thread-veiligheid, transparante afhandeling van opnieuw verbinden en een asynchrone API, waarvan Jedis alle functies mist.

Het is echter klein en aanzienlijk sneller dan de andere twee. Bovendien is het de clientbibliotheek bij uitstek van de Spring Framework-ontwikkelaars en heeft het de grootste community van alle drie.

3. Maven afhankelijkheden

Laten we beginnen met het aangeven van de enige afhankelijkheid die we nodig hebben in het pom.xml:

 redis.clients jedis 2.8.1 

Bekijk deze pagina als je op zoek bent naar de nieuwste versie van de bibliotheek.

4. Redis-installatie

U moet een van de nieuwste versies van Redis installeren en starten. We draaien op dit moment de laatste stabiele versie (3.2.1), maar elke post 3.x-versie zou in orde moeten zijn.

Vind hier meer informatie over Redis voor Linux en Macintosh, ze hebben zeer vergelijkbare basisinstallatiestappen. Windows wordt officieel niet ondersteund, maar deze poort wordt goed onderhouden.

Daarna kunnen we er direct in duiken en er verbinding mee maken via onze Java-code:

Jedis jedis = nieuwe Jedis ();

De standaardconstructor werkt prima, tenzij je de service hebt gestart op een niet-standaardpoort of een externe machine, in welk geval je deze correct kunt configureren door de juiste waarden als parameters door te geven aan de constructor.

5. Redis-gegevensstructuren

De meeste native bewerkingsopdrachten worden ondersteund en, handig genoeg, hebben ze normaal gesproken dezelfde methodenaam.

5.1. Snaren

Tekenreeksen zijn de meest basale soort Redis-waarde, handig als u eenvoudige sleutelwaarde-gegevenstypen wilt behouden:

jedis.set ("events / city / rome", "32,15,223,828"); String cachedResponse = jedis.get ("events / city / rome");

De variabele cachedResponse zal de waarde behouden 32,15,223,828. In combinatie met expiration-ondersteuning, die later wordt besproken, kan het werken als een razendsnelle en eenvoudig te gebruiken cachelaag voor HTTP-verzoeken die worden ontvangen in uw webtoepassing en andere cachevereisten.

5.2. Lijsten

Redis-lijsten zijn eenvoudig lijsten met strings, gesorteerd op volgorde van invoeging en maken het een ideaal hulpmiddel om bijvoorbeeld berichtenwachtrijen te implementeren:

jedis.lpush ("wachtrij # taken", "firstTask"); jedis.lpush ("wachtrij # taken", "secondTask"); String task = jedis.rpop ("wachtrij # taken");

De variabele taak zal de waarde behouden firstTask. Onthoud dat u elk object kunt serialiseren en het als een tekenreeks kunt behouden, zodat berichten in de wachtrij indien nodig complexere gegevens kunnen bevatten.

5.3. Sets

Redis-sets zijn een ongeordende verzameling strings die van pas komen als u herhaalde leden wilt uitsluiten:

jedis.sadd ("bijnamen", "bijnaam # 1"); jedis.sadd ("bijnamen", "bijnaam # 2"); jedis.sadd ("bijnamen", "bijnaam # 1"); Stel nicknames = jedis.smembers ("nicknames"); boolean bestaat = jedis.sismember ("nicknames", "nickname # 1");

De Java-set bijnamen heeft een grootte van 2, de tweede toevoeging van bijnaam # 1 werd genegeerd. Ook de bestaat variabele heeft de waarde waar, de methode sismember stelt u in staat om snel het bestaan ​​van een bepaald lid te controleren.

5.4. Hashes

Redis Hashes brengen in kaart tussen Draad velden en Draad waarden:

jedis.hset ("gebruiker # 1", "naam", "Peter"); jedis.hset ("gebruiker # 1", "baan", "politicus"); String name = jedis.hget ("gebruiker # 1", "naam"); Kaartvelden = jedis.hgetAll ("gebruiker # 1"); String job = fields.get ("job");

Zoals u kunt zien, zijn hashes een erg handig gegevenstype wanneer u de eigenschappen van objecten afzonderlijk wilt benaderen, aangezien u niet het hele object hoeft op te halen.

5.5. Gesorteerde sets

Gesorteerde sets zijn als een set waarbij elk lid een bijbehorende rangorde heeft, die wordt gebruikt om ze te sorteren:

Kaartscores = nieuwe HashMap (); scores.put ("PlayerOne", 3000.0); scores.put ("PlayerTwo", 1500.0); scores.put ("PlayerThree", 8200.0); scores.entrySet (). forEach (playerScore -> {jedis.zadd (key, playerScore.getValue (), playerScore.getKey ());}); String player = jedis.zrevrange ("ranking", 0, 1) .iterator (). Next (); long rank = jedis.zrevrank ("ranking", "PlayerOne");

De variabele speler zal de waarde behouden PlayerThree omdat we de beste 1 speler ophalen en hij is degene met de hoogste score. De rang variabele heeft de waarde 1 omdat PlayerOne is de tweede in de ranglijst en de rangschikking is gebaseerd op nul.

6. Transacties

Transacties garanderen atomiciteit en threadveiligheid, wat betekent dat verzoeken van andere klanten nooit gelijktijdig worden afgehandeld tijdens Redis-transacties:

String friendsPrefix = "vrienden #"; String userOneId = "4352523"; String userTwoId = "5552321"; Transactie t = jedis.multi (); t.sadd (friendsPrefix + userOneId, userTwoId); t.sadd (friendsPrefix + userTwoId, userOneId); t.exec ();

U kunt zelfs het succes van een transactie afhankelijk maken van een specifieke sleutel door deze te 'bekijken' vlak voordat u uw Transactie:

jedis.watch ("vrienden # verwijderd #" + userOneId);

Als de waarde van die sleutel verandert voordat de transactie wordt uitgevoerd, zal de transactie niet met succes worden voltooid.

7. Pijplijnen

Wanneer we meerdere commando's moeten verzenden, kunnen we ze samen in één verzoek verpakken en verbindingsoverhead besparen door pijplijnen te gebruiken, het is in wezen een netwerkoptimalisatie. Zolang de bewerkingen onderling onafhankelijk zijn, kunnen we profiteren van deze techniek:

String userOneId = "4352523"; String userTwoId = "4849888"; Pijplijn p = jedis.pipelined (); p.sadd ("gezocht #" + userOneId, "parijs"); p.zadd ("ranking", 126, userOneId); p.zadd ("ranking", 325, userTwoId); Response pipeExists = p.sismember ("doorzocht #" + userOneId, "paris"); Reactie pipeRanking = p.zrange ("ranking", 0, -1); p.sync (); String bestaat = pipeExists.get (); Stel ranking = pipeRanking.get ();

Merk op dat we geen directe toegang krijgen tot de opdrachtantwoorden, in plaats daarvan krijgen we een Reactie instantie waaruit we het onderliggende antwoord kunnen opvragen nadat de pijplijn is gesynchroniseerd.

8. Publiceer / abonneer

We kunnen de Redis Messaging Broker-functionaliteit gebruiken om berichten te verzenden tussen de verschillende componenten van ons systeem. Zorg ervoor dat de threads van de abonnee en de uitgever niet dezelfde Jedis-verbinding delen.

8.1. Abonnee

Abonneer u en luister naar berichten die naar een kanaal zijn verzonden:

Jedis jSubscriber = nieuwe Jedis (); jSubscriber.subscribe (nieuwe JedisPubSub () {@Override public void onMessage (String-kanaal, String-bericht) {// handle bericht}}, "kanaal");

Abonneren is een blokkeermethode, u moet zich afmelden voor het JedisPubSub uitdrukkelijk. We hebben het onMessage methode, maar er zijn veel meer nuttige methoden beschikbaar om te negeren.

8.2. Uitgever

Stuur vervolgens eenvoudig berichten naar datzelfde kanaal vanuit de thread van de uitgever:

Jedis jPublisher = nieuwe Jedis (); jPublisher.publish ("kanaal", "testbericht");

9. Pooling van verbindingen

Het is belangrijk om te weten dat de manier waarop we met onze Jedis-instantie zijn omgegaan, naïef is. In een realistisch scenario wilt u geen enkele instantie in een omgeving met meerdere threads gebruiken, aangezien een enkele instantie niet thread-safe is.

Gelukkig kunnen we eenvoudig een pool van verbindingen met Redis maken die we op aanvraag kunnen hergebruiken, een pool die threadveilig en betrouwbaar is, zolang je de bron terugbrengt naar de pool als je er klaar mee bent.

Laten we het JedisPool:

laatste JedisPoolConfig poolConfig = buildPoolConfig (); JedisPool jedisPool = nieuwe JedisPool (poolConfig, "localhost"); private JedisPoolConfig buildPoolConfig () {laatste JedisPoolConfig poolConfig = nieuwe JedisPoolConfig (); poolConfig.setMaxTotal (128); poolConfig.setMaxIdle (128); poolConfig.setMinIdle (16); poolConfig.setTestOnBorrow (true); poolConfig.setTestOnReturn (true); poolConfig.setTestWhileIdle (true); poolConfig.setMinEvictableIdleTimeMillis (Duration.ofSeconds (60) .toMillis ()); poolConfig.setTimeBetweenEvictionRunsMillis (Duration.ofSeconds (30) .toMillis ()); poolConfig.setNumTestsPerEvictionRun (3); poolConfig.setBlockWhenExempted (true); retourneer poolConfig; }

Aangezien de poolinstantie threadveilig is, kunt u deze ergens statisch opslaan, maar u moet ervoor zorgen dat de pool wordt vernietigd om lekken te voorkomen wanneer de toepassing wordt afgesloten.

Nu kunnen we indien nodig overal in de applicatie gebruik maken van onze pool:

probeer (Jedis jedis = jedisPool.getResource ()) {// voer bewerkingen uit met jedis resource}

We hebben de Java-instructie try-with-resources gebruikt om te voorkomen dat u de Jedis-resource handmatig moet sluiten, maar als u deze instructie niet kunt gebruiken, kunt u de resource ook handmatig sluiten in de Tenslotte clausule.

Zorg ervoor dat u een pool gebruikt zoals we in uw applicatie hebben beschreven als u geen vervelende multi-threading-problemen wilt ondervinden. U kunt natuurlijk spelen met de poolconfiguratieparameters om deze aan te passen aan de beste setup in uw systeem.

10. Redis-cluster

Deze Redis-implementatie biedt gemakkelijke schaalbaarheid en hoge beschikbaarheid, we raden u aan om hun officiële specificatie te lezen als u er niet bekend mee bent. We zullen de installatie van Redis-clusters niet behandelen, aangezien dat een beetje buiten het bereik van dit artikel valt, maar u zou er geen problemen mee moeten hebben als u klaar bent met de documentatie.

Zodra we dat klaar hebben, kunnen we het gaan gebruiken vanuit onze applicatie:

probeer (JedisCluster jedisCluster = nieuwe JedisCluster (nieuwe HostAndPort ("localhost", 6379))) {// gebruik de jedisCluster-bron alsof het een normale Jedis-bron is} vangst (IOException e) {}

We hoeven alleen de host- en poortgegevens van een van onze masterinstances op te geven, het zal de rest van de instances in het cluster automatisch detecteren.

Dit is zeker een zeer krachtige functie, maar het is geen wondermiddel. Wanneer u Redis Cluster gebruikt, kunt u geen transacties uitvoeren of pijplijnen gebruiken, twee belangrijke functies waarop veel toepassingen vertrouwen om de gegevensintegriteit te waarborgen.

Transacties zijn uitgeschakeld omdat in een clusteromgeving de sleutels in meerdere instanties worden bewaard. De atomiciteit van de bewerking en de veiligheid van de thread kunnen niet worden gegarandeerd voor bewerkingen waarbij opdrachten in verschillende gevallen worden uitgevoerd.

Sommige geavanceerde strategieën voor het maken van sleutels zorgen ervoor dat gegevens die voor u interessant zijn om in dezelfde instantie te worden bewaard, op die manier worden bewaard. In theorie zou dat u in staat moeten stellen om met succes transacties uit te voeren met behulp van een van de onderliggende Jedis-instanties van het Redis-cluster.

Helaas kunt u momenteel niet achterhalen in welke Redis-instantie een bepaalde sleutel is opgeslagen met Jedis (die feitelijk native wordt ondersteund door Redis), dus u weet niet in welke instanties u de transactie moet uitvoeren. Mocht u hierin geïnteresseerd zijn, dan kunt u hier meer informatie vinden.

11. Conclusie

De overgrote meerderheid van de functies van Redis zijn al beschikbaar in Jedis en de ontwikkeling gaat in een goed tempo vooruit.

Het geeft u de mogelijkheid om met weinig moeite een krachtige in-memory storage-engine in uw applicatie te integreren. Vergeet niet om verbindingspooling op te zetten om veiligheidsproblemen met threads te voorkomen.

U kunt codevoorbeelden vinden in het GitHub-project.