Wat is Redis Streams?

Redis Streams is een datastructuur binnen Redis waarmee berichten en events als een geordende stroom kunnen worden verwerkt. Waar je Redis misschien vooral kent als snelle key-value store of cache, maakt Redis Streams het mogelijk om Redis ook in te zetten voor asynchrone communicatie tussen processen en services.

Berichten blijven binnen een stream beschikbaar totdat je ze bewust verwijdert. Met Consumer Groups kunnen meerdere consumers samen berichten verwerken, waarbij Redis bijhoudt welk bericht door welke consumer is opgepakt en of de verwerking daadwerkelijk is afgerond.

Voor mij zit de kracht vooral in de combinatie van snelheid, eenvoud en controle over de verwerking.

Belangrijke dingen om te weten

Consumer Groups

Consumer Groups maken het mogelijk om meerdere instances van een applicatie gezamenlijk dezelfde stream te laten verwerken.

Een bericht wordt binnen een Consumer Group aan één consumer toegewezen. Hierdoor kun je verwerking horizontaal schalen zonder dat iedere instance automatisch hetzelfde bericht verwerkt.

Acknowledgements

Een bericht ophalen betekent niet direct dat het succesvol verwerkt is.

Met acknowledgements bevestigt een consumer expliciet dat de verwerking klaar is. Berichten die niet correct worden afgerond blijven zichtbaar als pending en kunnen opnieuw worden opgepakt.

Dat maakt Redis Streams een stuk betrouwbaarder dan een constructie waarbij een bericht na uitlezen direct verdwenen is.

Pending Entries

Redis houdt binnen een Consumer Group bij welke berichten zijn geleverd, maar nog niet zijn bevestigd.

Dat is belangrijk bij bijvoorbeeld:

  • een crash tijdens verwerking;

  • time-outs naar externe systemen;

  • langlopende processen;

  • tijdelijke fouten;

  • het opnieuw verdelen van werk tussen consumers.

Juist die controle over wat er nog verwerkt moet worden maakt Streams interessant voor robuuste backend-processen.

Ordering

Ieder bericht krijgt een oplopende Stream ID. Daarmee blijft de volgorde van berichten binnen een stream inzichtelijk.

Dat betekent niet automatisch dat iedere gedistribueerde verwerking volledig sequentieel moet plaatsvinden, maar het geeft je wel een duidelijke basis voor processen waarbij volgorde relevant is.

Redis Streams is geen Kafka

Redis Streams en Kafka lossen deels vergelijkbare problemen op, maar hebben een andere positie.

Kafka zie ik eerder als een volwaardig distributed event platform voor grote event-driven landschappen, hoge volumes en langdurige event-retentie.

Redis Streams vind ik juist sterk wanneer Redis al onderdeel is van het platform en je zonder onnodige infrastructuur een betrouwbare asynchrone workflow wilt realiseren.

De keuze hoort wat mij betreft dus vanuit het probleem te komen, niet vanuit de populariteit van de technologie.

Hoe ik Redis Streams gebruik

Ik gebruik Redis Streams voornamelijk voor processen waarbij werkzaamheden asynchroon, betrouwbaar en schaalbaar uitgevoerd moeten worden.

Mijn voorkeur gaat daarbij uit naar een duidelijke flow:

Producer → Stream → Consumer Group → Worker → Acknowledge

De producer publiceert alleen wat er uitgevoerd moet worden. Workers binnen een Consumer Group voeren het daadwerkelijke werk uit en bevestigen pas na succesvolle verwerking het bericht.

Daaromheen ontwerp ik bewust zaken zoals:

  • retries;

  • foutafhandeling;

  • idempotency;

  • monitoring;

  • recovery van vastgelopen berichten;

  • schaalbaarheid van consumers.

Het publiceren van een bericht is namelijk het eenvoudige gedeelte. Een goed ontwerp ontstaat vooral door na te denken over wat er gebeurt wanneer de verwerking niet volgens het ideale pad verloopt.

Mijn recente ervaring met Redis Streams

Ik werk inmiddels ongeveer vijf jaar met Redis en Redis Streams. Binnen mijn backend-werk gebruik ik Redis niet alleen als snelle datastore, maar juist ook als onderdeel van distributed en event-driven architecturen.

Een concreet voorbeeld daarvan is mijn werk binnen het Car Platform van ANWB.

Daar werkte ik aan een platform dat sterk afhankelijk was van externe databronnen. Een belangrijk probleem was dat verschillende processen lang konden duren en dat de verwerking daarvan betrouwbaar georkestreerd moest worden.

Ik heb daar een volledig asynchrone Task Scheduler ontwikkeld met Kotlin Coroutines en Redis. Vervolgens heb ik de overstap naar Redis Streams geleid als vervanging voor een handmatig beheerd queue-mechanisme.

Daarmee kregen we onder andere:

  • betrouwbaardere berichtverwerking;

  • betere controle over onafgeronde taken;

  • hogere throughput;

  • betere monitoring;

  • eenvoudiger horizontaal schalen;

  • minder zelfgebouwde queue-logica.

Die ervaring heeft voor mij vooral bevestigd dat duurzaamheid in software niet altijd betekent dat je méér infrastructuur moet toevoegen.

Soms is de betere architectuur juist degene waarbij je bestaande componenten slimmer inzet en daarmee complexiteit verwijdert.

Dat past ook bij hoe ik backend-systemen ontwerp: eerst begrijpen wat het probleem daadwerkelijk vraagt en daarna de eenvoudigste oplossing kiezen die ook onder fouten betrouwbaar blijft.

Wanneer kies ik voor Redis Streams?

Redis Streams vind ik vooral interessant wanneer:

  • Redis al onderdeel is van de infrastructuur;

  • verwerking asynchroon moet plaatsvinden;

  • berichten niet zomaar verloren mogen gaan;

  • meerdere workers gezamenlijk taken moeten verwerken;

  • retry- en recovery-mechanismen nodig zijn;

  • Goedkoper dan Kafka

Voor grote event-driven platformen, langdurige event-retentie of veel onafhankelijke consumers zou ik eerder richting Kafka kijken.

Voor compacte, snelle en betrouwbare asynchronous processing kan Redis Streams juist uitzonderlijk goed passen.

Veelgestelde vragen die ik krijg over Redis Streams

Waarom Redis Streams en niet gewoon Kafka?

Omdat niet ieder asynchroon proces een volledig event-platform nodig heeft. Bij ANWB was Redis al aanwezig en bood Redis Streams precies de garanties die we nodig hadden. Minder infrastructuur, minder beheer en toch betrouwbare verwerking.

Is Redis Streams hetzelfde als een queue?

Niet helemaal. Het kan als queue gebruikt worden, maar berichten blijven onderdeel van een stream. Met Consumer Groups, acknowledgements en pending entries krijg je daardoor veel meer controle over verwerking en recovery.

Kun je Redis Streams vertrouwen voor kritieke processen?

Ja, mits je het goed ontwerpt. Ik kijk daarbij vooral naar acknowledgements, retries, idempotency, persistence en recovery. De technologie helpt je, maar betrouwbaarheid ontstaat uiteindelijk door het complete proces goed te ontwerpen.

Waarom heb je bij ANWB het bestaande queue-systeem vervangen?

Omdat er te veel queue-functionaliteit handmatig werd beheerd die Redis Streams standaard al goed oplost. Door terug te gaan naar een bewezen mechanisme werd de architectuur eenvoudiger, beter observeerbaar en betrouwbaarder.

Wanneer zou je Redis Streams juist niet gebruiken?

Wanneer Streams langzaam het centrale event-platform van een groot landschap begint te worden. Als veel domeinen onafhankelijk events moeten consumeren, lange retentie belangrijk wordt of replay een belangrijke capability is, kijk ik eerder naar Kafka.