Transkript

Redis in der Praxis

Überblick und praktischer Einsatz des schnellen Datenstruktur-Servers

In dieser Episode unterhalten sich Lucas Dohmen und Stefan Tilkov über Redis, eine NoSQL-Datenbank aus der Key-Value-Kategorie, die sich insbesondere durch ihre hohe Geschwindigkeit und ihre intelligenten Datenstrukturen auszeichnet. Dabei werden nicht nur die Features aufgezählt, sondern auch praktische Hinweise zum Einsatz gegeben.

Zurück zur Episode

Transkript

Lucas Dohmen: Hallo.

Stefan Tilkov: Wie immer ist meine erste Frage an Dich, erzähl doch ganz kurz wer Du bist und was Du bei uns tust.

Lucas Dohmen: Ja, ich bin der Lucas, ich arbeite bei innoQ als Consultant. Ich consulte vor allem als Ruby- und Javascript-Entwickler in Verbindung mit NoSQL Datenbanken – Redis aktuell im Projekt, aber ich interessiere mich eigentlich für alle NoSQL Datenbanken: wofür man die einsetzen kann, wofür man die nicht so gut einstezten kann, wann man welche einsetzt - da helfe ich gerne Leuten weiter, da das richtige zu finden.

Stefan Tilkov: Alles klar. Deswegen haben wir uns heute eine dieser Datenbanken ausgesucht - nämlich, Du hast es schon erwähnt, Redis, und dachte wir reden einfach mal ein bisschen darüber, was das eigentlich ist, was man damit tun kann, welche Stärken und Schwächen es hat. Schauen wir mal, wohin uns die Diskussion führt. Du hast vorhin schon NoSQL (gesprochen: NoSequel) gesagt, kannst Du da vielleicht Redis mal so ein bisschen einsortieren, in dieses große Universum schlecht definierter Kategorien?

Lucas Dohmen: Ja, also allgemein würde Redis in die Kategorie von Key Value Stores gepackt. Ein „Key Value Store“ ist ursprünglich erstmal die Idee: man hat Keys und man hat Values und man kann Werte abfragen, indem man sagt, „Gib mir bitte den Value zu diesem Key“. Und das, was in diesem Value drinsteht, das interessiert die Datenbank an sich, also den Key Value Store, erstmal nicht. Das heisst, da kann drinstehen drin stehen was man will, da sind keine sekundären Indizes drauf, da kann jetzt irgendwie binär was drin sein oder ein String oder eine Zahl, das ist erstmal egal. Ich frage nach dem Key und ich kriege den Value zurück. Das ist erstmal die grundsätzliche Idee.

Stefan Tilkov: Eine Hashmap mit anderen Worten.

Lucas Dohmen: Genau, eine Hashmap quasi als Server. Das ist auch der Urpsrung des Namens Redis. Redis heisst „Remote Dictionary Server“ und das ist genau das, was du da beschrieben hast. In Python heisst es ja, glaube ich, Dictionary und in Ruby heißt es Hash und es hat ja immer verschiedene Namen, aber genau das ist es eigentlich im Kern. Nun haben die Leute irgendwann festgestellt, mit exakt nur dieser einen Funktionalität hat man irgendwann das Bedürfnis vielleicht doch ein bisschen mehr damit zu machen. Deswegen haben sich eigentlich alle Datenbanken, die man in dieser Kategorie findet, weiterentwickelt und haben weitere Fähigkeiten dazu entwickelt und sind deswegen nicht mehr reine Key Value Stores.

Stefan Tilkov: Gibt es überhaupt irgendeinen reinen Key Value Store, der das nicht getan hat?

Lucas Dohmen: Ja, ich würde sagen Memcash, der das irgendwie behalten hat – diesen Ursprungssinn davon – aber alle anderen haben schon andere Sachen entwickelt. Redis hat sich in die Richtung von Datenstrukturen entwickelt. Also manche nennen den auch einen Datenstruktur-Server und das macht es zu einem relativ attraktiven Allzweckwerkzeug, das Redis ist.

Stefan Tilkov: Als ich mich mit Redis mal beschäftigt habe – das ist schon 'ne Weile her, 2–3 Jahre oder so, da fand ich vor allem toll, dass es so schlank und leichtgewichtig und klein war. Ist das immer noch so oder ist das mittlerweile so fett geworden, dass man keine Lust mehr hat das runterzuladen, weil man…

Lucas Dohmen: Also, das ist wirklich winzig klein, läuft immernoch single threaded, ist auch eine der Sachen, was viele Leute zu Redis bringt, dass man einfach das Gefühl hat, man versteht, was da passiert. Wenn man jetzt vor Postgres sitzt, da sagt man erstmal „Okay…was passiert da noch?“ – da sind so viele Sachen drin, allein wieviel Sourcecode das ist. Redis ist im Vergleich wirklich sehr sehr klein. An manchen Stellen finde ich, da kommen manchmal schon so Sachen dazu, wo man denkt, „Ah okay, passt das noch zu dem ursprünglichen Ding?“, aber ich glaube, das trifft auf so gut wie jede Datenbank zu. Von diesem „Feature Creep“ sind Datenbanken einfach nicht ausgenommen, aber ändert nichts dran, dass es meines Erachtens nach immer noch sehr schlank ist.

Stefan Tilkov: Du hast diese Datenstrukturen schon erwähnt – das ganze als Datenstrukturserver. Was sind das denn für Datenstrukturen, außer BLOBS oder Wide Arrays, die noch so drin sind?

Lucas Dohmen: Also grunsätzlich, erstmal der ursprüngliche Datentyp ist etwa der String. Ein String darf bis zu 512 MB groß sein, ist natürlich wichtig, wenn man das jetzt als Replacement für Memcached benutzt, da will man ja vielleicht 'ne ganze Website als Key reinhauen, da möchte man schon Platz haben.

Stefan Tilkov: Als Value reinhauen.

Lucas Dohmen: Ja, entschuldigung,

Stefan Tilkov: Ja, passiert mir immer.

Lucas Dohmen: Diese Strings sind immer so Allzweckwerkzeuge. Man kann sie auch, wenn man sie im Memory drin hat, auf veschiedene Arten und Weisen betrachten. Man kann sie als String betrachten, man kann ihn setzen und wieder wegsetzen und so weiter. Man kann ihn aber auch als Integer betrachten. Wenn ich da die Zahl „fünfzehn“ reinschreibe, dann kann ich eine Operation auf diesen String ausführen, die heisst Increment, dann wird daraus der String „sechzehn“. Dass heisst, es nicht nur ein String, man kann ihn auch auf andere Art und Weise interpretieren – auch als Bitmap kann man ihn betrachten. Da kann man einzelne Bits in diesem String umsetzen.

Das ist erstmal so das Brot–und–Butter-Ding, was man immer wieder braucht. Aber es gibt auch weitere Datenstrukturen, eine davon ist die Liste. Liste ist einfach eine Sequenz von Strings. Da kann man ganz viele Strings hintereinander haben. Man kann dann auf die Strings an verschiedenen Stellen zugreifen, man kann sagen: „gib mir mal den fünften Eintrag“, wie man das jetzt irgendwie als Array kennt in einer Programmiersprache.

Dabei sind die Listen aber so, dass wir verschiedene Operationen darauf haben und so können wir sie auf verschiedene Art und Weise benutzen. Wir können sie zum Beispiel als Queue benutzen, indem wir als Operation immer nur von links reinschreiben und von rechts rauslesen. Und so können wir es dann als Queue benutzen. Es bleibt aber dieselbe Datenstruktur, es bleibt eine Liste. Aber diese Eigenschaft hat halt viele Leute dazu gebracht, Redis auch als Jobqueue zu benutzen. Weil, wir haben ja jetzt die Möglichkeit, einfach von reinzuschreiben mit unserem Producer und die Konsumenten, die warten darauf, dass Einträge in diese Liste kommen.

Und dafür hat Redis auch zum Beispiel blockende Operationen, das heißt, ich kann sagen „Ich möchte bitte aus dieser Liste den letzten Eintrag haben“ und ich blocke solange, bis ein Eintrag in diese Liste reinkommt. Wenn keiner drin ist, warte ich einfach. Und Redis sorgt dann dafür, dass wenn 15 Leute auf diesen Eintrag warten, dass wenn dann ein neuer Eintrag kommt, dann wird er an den Ersten geschickt und die 14 anderen warten weiter. Und damit kann man dann halt selbst auch eine Jobqueue bauen, das haben viele, viele Leute schon gemacht. So in der Ruby–Welt gibt es da jetzt irgendwie Resque Queue und Sidekiq. All die basieren auf Redis unten drunter. Aber es ist halt keine Jobqueue, es ist nicht die Datenstruktur Queue, es gibt jetzt nicht irgendwie retries oder sowas, das ist nicht mit da drin. Und da das den antirez, den Erfinder von Redis, ein bisschen geärgert hat, dass die Leute seinen schönen Datenstruktur–Server immer als Queue benutzen, hat er mittlerweile eine Queue geschrieben als separate Software, die Disque heißt.

Stefan Tilkov: Verstehe. Wer 'ne Queue benutzen will, soll bitte dieses Ding benutzen, und nicht Redis dafür missbrauchen.

Lucas Dohmen: Genau, richtig.

Stefan Tilkov: Weil du das gerade erwähnt hast – mir war nicht so ganz klar, was für Garantien jetzt eigentlich an dieser Liste dranhängen. Also gibt es bei den Operationen, die man da machen kann, entsprechende Aussagen zur Laufzeit–Performance, zur Komplexität von diesen Dingern?

Lucas Dohmen: Genau. Eine der Sachen, die wirklich, für mich zumindest, sehr interessant ist an Redis' Dokumentation, ist, dass man für alle Operationen Laufzeitinformationen kriegt. Bei jedem steht dabei, was ist die Laufzeit von dieser Operation. Das kenne ich so von anderen Dokumentationen eigentlich eher nicht. Oder, man sieht es eher selten. Das heißt, wenn einen das interessiert, was ist jetzt die Laufzeit von dieser bestimmten Operation, dann kann man das ganz schnell nachschauen.

Stefan Tilkov: Ich glaube, wir meinen beide das Gleiche, mit Laufzeit meinen wir dann irgendwie Komplexität, im Sinne von „wie hängt das von der Anzahl Elemente da drin ab“.

Lucas Dohmen: Genau.

Stefan Tilkov: Also: wir haben Strings, wir haben Listen, die man auf verschiedene Arten benutzen kann, gibt es noch mehr?

Lucas Dohmen: Ja, es gibt noch mehr, es gibt zum Beispiel Sets, wie man das auch wieder als Datenstruktur kennt – deswegen, ne, immer wieder kommt zurück, dieser Datenstruktur-Server – alles, was man so aus seinen Datenstruktur-Vorlesungen oder vielleicht aus irgendwelchen Blogposts kennt, das sind so die Sachen, die da mit dabei sind. Das heißt, die Elemente in einem Set sind einzigartig, jedes Element darf nur einmal drin sein. Das kann man für verschiedenste Dinge benutzen, man möchte irgendwie 'nen Warenkorb haben, wo jedes Ding nur einmal drin sein darf oder so, das kann man alles mit einem Set abbilden. Und eine Abart davon ist halt das „sorted Set“. Da ist zusätzlich zu jedem Eintrag in dem Set ein Float Value, der „Rank“, zugeordnet, das heißt, ich kann da jetzt zum Beispiel Namen reinsetzen, und als Rank dann das Geburtsdatum der Person reintun, das ist ja auch ein Float. Oder ähm, oder das Geburtsjahr –

Stefan Tilkov: Geburtsdatum ist ein Float, ganz eindeutig –

Lucas Dohmen: Ja, als Unix–Timestamp, ne (Lachen). Also, das Geburtsjahr. Und jetzt möchte ich – weil es sorted ist, kann ich sagen „Gib mir jetzt alle, bei dem dieser Rank zwischen 1950 und 1960 liegt“. Und so kriege ich alle Werte zurück, also alle Personen zurück, die in diesen Jahren geboren sind. Da kann man sich jetzt auch wieder sehr viele verschiedene Sachen ausdenken, wofür man sowas braucht. Und es ist halt wieder dieses – was mir an Redis immer so gut gefällt, ist halt diese Einfachheit. Es ist nicht jetzt so, ich kann jetzt beinm sorted Set noch tausend verschiedene Sachen einstellen. Man hat halt – man ordnet dem ein Float Value zu. Und es gibt dann noch ein paar Sachen, wie man diesen Float Value automatisch erzeugen kann und so weiter, aber das grundsätzliche bleibt immer gleich. Ich hab immer irgendwelche Werte, und dazu gehört ein Float Value. Und das finde ich halt sehr elegant.

Und auch hier wieder sind die Einträge wieder Strings, das heißt, da gelten wieder alle Sachen, die man über den String gesagt hat. Ja und, der letzte Datentyp ist halt noch der Hash, da hat man ähnlich wie bei einem Dictionary einen Key und ein Value. Aber der Value darf jetzt nicht wieder ein Hash sein oder so, sondern der Key ist ein String, der Value ist ein String. Und das wars. Da kann man dann Zuordnungen machen.

Stefan Tilkov: Das heißt, wenn man jetzt beliebig komplizierte, verschachtelte Strukturen hätte, würde man die halt mit mehreren solchen Dingen abbilden. Dann hätte man vielleicht als erste Stufe irgendwelche Hashes, hinter denen sich dann – also erstmal klar, wir haben Key-Values in den Key-Values, in den Key-Values selbst, also einfach die primäre Key-Value Variante, die Values wären dann wiederum vielleicht Hashes, die ihrerseits dann vielleicht wieder auf irgendwas anderes zeigen, da kann ich auch wieder irgendwelche Keys unterbringen, wenn ich das nochmal rekursiv haben möchte.

Lucas Dohmen: Genau.

Stefan Tilkov: Das heißt aber doch auch, wenn ich eine beliebige Domäne irgendwie abbilden will, ein beliebiges Datenmodell da reinbringen will, dann mache ich im Prinzip mir selbst Gedanken darum, wie das am besten abzubilden ist auf diese bestehenden Elemente. Das heißt, wenn ich jetzt zum Beispiel auf verschiedene Arten abfragen will, dann muss ich mir selber überlegen, wie ich das dafür ablegen muss, damit nachher diese Abfrage, die ich machen will, vernünftig funktioniert. Richtig?

Lucas Dohmen: Genau, so isses.

Stefan Tilkov: Ok. Also, wenn ich jetzt irgendwas reinschreibe, dann muss ich vielleicht einen Index selberbauen, den ich irgendwo aktualisiere.

Lucas Dohmen: Genau. Das ist das, was halt an Redis so charmant ist – man weiß halt genau, was passiert. Es passieren nicht irgendwelche magischen Dinge im Hintergrund, man hat halt direkte Kontrolle darüber, was passiert. Das hat natürlich auch den Nachteil, wenn ich jetzt irgendwie einen Sekundärindex will, dann muss ich den halt irgendwie basteln, indem ich dafür beispielsweise jetzt die sorted Sets benutze. Dann kann ich die halt benutzen, um einen Sekundärindex aufzubauen.

Dann bin ich aber auch dafür verantwortlich, den zu pflegen. Wenn ich jetzt irgendwas ändere an dem Element, muss ich auch dafür sorgen, dass der Index geupdated wird. Was einem natürlich jetzt eine klassische Datenbank abnimmt, diesen Job. Aber wenn man diese Mühe nicht scheut, dann hat man da halt sehr hohe Kontrolle drüber.

Stefan Tilkov: Ok.

Lucas Dohmen: Es gibt nur noch zwei Sachen, die relativ neu sind als Datentyp, das habe ich gerade noch vergessen. Einmal der Hyperlock, das ist eigentlich ein Set, also man kann da unique Items wieder reinlegen, also unique Strings. Aber er zählt, wie oft jedes Item reingelegt wurde. Das ist um Sachen zu zählen, und das bildet es sehr sehr performant ab.

Stefan Tilkov: Weil offensichtlich Leute das häufiger gebraucht haben.

Lucas Dohmen: Ja. Oder weil einfach antirez diese Datenstruktur interessant fand, das kann durchaus auch der Grund sein, warum das eingebaut wurde. Nicht auszuschließen.

Stefan Tilkov: Hat sich übrigens ziemlich eingebürgert, man redet von antirez und meint damit diesen Salvatore Sanfilip – heißt der so?

Lucas Dohmen: Sanfilippo, ja.

Stefan Tilkov: Das ist halt sein Twitterhandle, oder der Name seiner Domain oder so.

Lucas Dohmen: Es ist halt einfacher, gerade wenn man nicht so einen schönen Akzent hat, wie er, das schön auszusprechen.

Und dann gibt es noch ganz, ganz neu, ich weiß gar nicht, ob das im offiziellen Release schon drin ist, gibt es noch Geo-Indizes als Datenstruktur. Da kann ich dann so Sachen machen, wie: „Gib mir alle Sachen, die in der Nähe von der und der Geo-Koordinate liegen“ oder die in dem Radius liegen.

Stefan Tilkov: So spatial query mäßig.

Lucas Dohmen: Genau, genau. Und da gibt es ja schon existierende Lösungen wie zum Beispiel PostGIS von Postgres oder so, aber hier wieder in diesem separaten Store. Und das wars dann.

Stefan Tilkov: Ok. Wir haben vorhin kurz darüber gesprochen, dass gewisse Ähnlichkeit zu Memcached da ist, Memcached hat im Namen ja schon das Caching. Wie ist das bei Redis, wie sieht’s da mit der Persistenz aus und mit den Anforderungen, das alles in den Hauptspeicher passt oder nicht? Kannst du dazu kurz was sagen?

Lucas Dohmen: Ja, also Redis ist eine Memory Database. Also alles muss in den Hauptspeicher passen. Und das ist natürlich auch das, was es so schnell macht. Redis ist halt eine wirklich, wirklich schnelle Datenbank.

Stefan Tilkov: Was heißt denn wirklich schnell. Kann man das beziffern? Was bedeutet denn schnell?

Lucas Dohmen: Ähm, also beziffern, es ist auf jeden Fall – wenn man schon mal Memcached benutzt hat, um irgendwelche Operationen da zu machen, ist es halt genau so schnell oder vergleichbar schnell zu Memcached. Jetzt wieviele Insertions pro Minute, sowas –

Stefan Tilkov: Ok, schreiben wir in die Shownotes. Wir suchen das heraus. Ich glaube es sind verdammt viele.

Lucas Dohmen: Ja, es sind sehr sehr viele, es ist sehr, sehr imposant, wieviel das so schafft.

Stefan Tilkov: Ok. Es muss alles in den Hauptspeicher passen, das heißt aber nicht, dass es nur ein Cache ist, sondern es wird auch persistiert.

Lucas Dohmen: Genau. Also in Redis gibt es grundsätzlich drei verschiedene – es gibt erstmal – grundsätzlich kann man sagen „Redis, du bist nur im Hauptspeicher, wenn du runterfährst dann sind alle Daten weg“. Diesen Modus gibt es. Und das ist auch der Modus, in dem ich meistens Redis betreibe. Das heißt, wenn der jetzt irgendwie abstürzen sollte, dann sind die Daten halt weg.

Es gibt aber noch zwei Optionen, die man anschalten kann, das eine ist Snapshotting. Das heißt, alle – in jedem Zeitintervall, das man selber konfigurieren kann, wird ein Snapshot auf die Platte geschrieben. Das ist natürlich praktisch für irgendwie Backups, dann kann ich jetzt irgendwie wiederherstellen, wie war es am 24. letzten Monat, was war da in der Redis drin, kann ich das halt mir ziehen, wie ich das jetzt auch bei Mysql oder sowas machen kann.

Aber es gibt dann auch noch das Append-only-File. Das heißt, alle Operationen, die ausgeführt werden, werden auch in dieses Append-only-File reingeschrieben. Das bedeutet, dass wir, wenn die Datenbank abstürzt, also wenn Redis abstürzt, können wir diese Datei replayen. Das heißt, da werden einfach alle Operationen nacheinander – halt viel, viel schneller, weil, ne, sie ja sofort hintereinander ausgeführt werden – wieder ausgeführt und wir stellen so den State wieder her, den wir vorher hatten. Dabei ist es natürlich auch so, dass, wenn wir jetzt natürlich einen Key angelegt haben und ihn später gelöscht haben, da steht sowohl das Anlegen als auch das Löschen drin, das wird jetzt nicht kompakter gemacht. Aber man kann kann dann auch – ich glaube nicht mit Hausmitteln, aber man kann das halt natürlich auch kompakter machen. Und dann halt so sagen, „Hey wenn das passiert, dann mach das halt kleiner und lösch das erste Command“ oder sowas.

Es ist halt die Empfehlung von den Redis–Leuten, dass man den Append-only-File benutzen sollte, wenn man möchte, dass es bei einem Absturz es schnell wiederhergestellt werden kann. Und das Snapshotting für Backups.

Stefan Tilkov: Ok. Und werden die beiden dann kombiniert? Also, kann ich sagen, jetzt habe ich einen Snapshot von da, und ab da alles, was ich danach im Journal stehen habe oder stelle ich mir das falsch vor?

Lucas Dohmen: Also, man kann beides gleichzeitig anschalten, aber die beiden kooperieren nicht miteinander. Man kann jetzt nicht sagen, „Hey, da ist das letzte Backup, von da an benutze das Append-only-File“. Sondern, das Append-only- File enthält immer alle Transaktionen.

Stefan Tilkov: Ok, verstehe. Gut. Vielleicht kannst du uns noch was zu – lass mich überlegen, wie wir das machen – lass mich so rum fragen: Du hast vorhin gesagt, dass du das meistens so benutzt, dass du die Persistenz nicht nutzt. Also, du sagst einfach, „Wenn die Daten weg sind, sind sie weg“. Daraus schließe ich, dass du das nicht als primäre Datenbank benutzt. Für was für Einsatzzwecke benutzt du es denn, kannst du ein bisschen was dazu erzählen, zu deinem aktuellen Projekt, ohne hier irgendwelche Details zu verraten?

Lucas Dohmen: Ja, also… Ich benutze Redis immer gerne um – zum einen halt als Cache, ich finde es halt ganz nett das zu benutzen, im Gegensatz zu Memcached, weil ich halt die Option habe, Daten ein bisschen cleverer abzulegen. Das heißt, ich muss nicht immer nur einfach alles von Key auf Value mappen, ich kann halt auch mal diese Datenstruktur benutzen, um Sachen ein bisschen schlauer abzulegen. Damit ich sie leichter wiederfinden kann, damit ich sie irgendwie zwischen verschiedenen Einträgen dann wiederverwenden kann.

Im aktuellen Projekt benutzen wir das als sehr, sehr einfachen Cache. Einfach nur Get, Set und Expire. Das zu irgendeinem Zeitpunkt, um Daten, die momentan in einer Datenbank liegen, die etwas überlastet ist, um die halt zu entlasten. Das heißt, die Daten werden von da geholt und dann werden sie mit einer bestimmten Zeit dann in diesen Cache reingelegt und dann können wir die abholen, anstatt immer auf die Datenbank drauf zu gehen. Das ist ja irgendwie so der Standard Use-Case, aber wir benutzen es auch für Inter-Prozess-Kommunikation. Und dafür finde ich halt Redis wirklich sehr charmant, weil es halt so viele verschiedene Dinge eingebaut hat, die man dafür benutzen kann.

Wir benutzen zum einen die Listen als Queue, das heißt, ich hab eine ganz, ganz kleine Queue-Implementierung gebaut, auf Basis davon. Die ist aber wirklich klein, also es sind irgendwie 50 Zeilen Javascript-Code, weil – das Grundsätzliche ist drin. Und das Queue-Monitoring, also das Beobachten davon, welche Jobs liegen zu lange auf der Queue, das habe ich in einem externen Prozess, der das auch wieder monitored. Das heißt, das ist ein separates Programm, was ich halt auch daran irgendwie ganz nett finde. Wir benutzen das, um Jobs zu verteilen, wir haben dabei bestimmte Anforderungen, die es attraktiver machen, diese Queue halt – mehr Kontrolle über diese Queue zu haben, als wenn man dabei einfach ein fertiges RabbitMQ oder sowas benutzt. Und deswegen verwenden wir das. Und es war auch für uns ein Grund, uns dafür zu entscheiden, weil – wir brauchten sowieso einen Cache, und wir haben also jetzt schon Redis, wir haben die Möglichkeit, Redis-Docker-Container aufzusetzen, wenn wir jetzt auch noch eine Queue aufsetzen, dann sind das ja auch wieder Sachen, die man beim Betrieb wieder braucht. Wir müssten auch noch eine Queue bereitstellen, so haben wir diese Einfachheit, dass wir dafür das gleiche System benutzen können.

Und zum Dritten benutzen wir es als Pub/Sub-Server, das ist ein Feature in Redis, wo man Nachrichten auf einen bestimmten Channel draufschreiben kann und man kann als Konsument bestimmte Channel abonnieren. Dann kriegt man alle Nachrichten, die da draufgeschrieben werden, geliefert. Das ist natürlich anders, als bei der Queue. Bei der Queue ist es ja so: Wenn ich was reinschreibe, dann wird einer der Konsumenten die Nachricht kriegen, aber nicht alle. Und bei Pub/Sub schreibe ich es drauf und alle Konsumenten kriegen diese Nachricht. Und so mit diesen zwei Mechanismen, mit der Queue und diesem Pub/Sub, können wir die Kommunikationswege, die auf diesem System stattfinden, können wir die abbilden. Und dieses System ist in NodeJS geschrieben, weil NodeJS ist ja ein non-blocking Environment, was es halt sehr nett macht für Sachen, wo man Kommunikationswege abbildet, wo man meistens auf die Antwort von irgendeinem anderen System wartet und das dann wieder weiterleitet. Das heißt, ich bau so eine zentrale Komponente, die diese Kommunikation zwischen verschiedenen Komponenten steuert. Ne, damit irgendwelche Sachen dann passieren und dann passieren und dann passieren, und dafür benutze ich Redis eben mit den Queues und Pub/Sub, um dann die Nachrichten zu verteilen, auf die Art und Weise, wie ich es halt brauche.

Stefan Tilkov: Wie sieht das mit so anderen Features aus, die man von klassischen relationalen Datenbanken gewohnt ist? Also zum Beispiel Transaktionen, unterstützt Redis Transaktionen?

Lucas Dohmen: Ja, Redis unterstützt Transaktionen. Ich kann sagen – also, wir haben ja diese Datenstrukturen, und für jede Datenstruktur gibt es ja dann verschiedene Befehle, die wir ausführen können, wie jetzt zum Beispiel „Set“ eines Wertes. Wir können sagen, „Bitte führe diese 20 Operationen als eine Transaktion durch“. Das heißt, Redis garantiert uns, das zwischendurch kein anderer Client jetzt auch einen Befehl ausführen kann. Das wird also als eine Atomic Operation quasi ausgeführt. Und falls der Client in der Zwischenzeit irgendwie nicht mehr erreichbar ist von Redis aus, dann bricht er diese Transaktion ab, rollt sie zurück, und macht weiter, als wäre nichts passiert.

Stefan Tilkov: Das passt ja nun eigentlich dazu zu der Struktur, wenn das, wie du sagst, non-blocking, es single-threaded ist, dann ist es ja ohnehin so, dass zu einem Zeitpunkt immer nur ein Client etwas macht, und wenn ich dich gerade richtig verstanden habe, ist der Trick praktisch, dass man einfach mehrere Befehle auf einmal hinschickt. Das ist also nicht extra ein Transaktionsprotokoll, sondern man batcht einfach die zehn Befehle, die man gerne hätte, und weil er sowieso nur einen nach dem anderen ausführt, macht er das eben als Block.

Lucas Dohmen: Genau, das ist wieder das charmante, durch diese Einfachheit war das halt kein großer Aufwand, das zu bauen. Das einzig Besondere ist halt, dass, falls in der Zwischenzeit unerwartet mein Client nicht mehr da ist, dass es halt zurückgerollt wird.

Stefan Tilkov: Muss bei einer normalen Transaktion halt – ach so, du meinst im Gegensatz zu den Anderen – aber das wäre ja bei den anderen Befehlen wahrscheinlich genauso oder?

Lucas Dohmen: Ja, also wenn während – also die Befehle sind so schnell, mir ist noch nie ein Client während einem Befehl irgendwie weggebrochen – gute Frage, weiß ich nicht was dann passieren würde. Aber ich denke auch, dass es dann zurückgerollt werden würde.

Stefan Tilkov: Das bringt aber noch nicht die Frage auf, wenn ich schonmal bei enterprisey Features bin, was ist denn, wenn ich das Ganze skalieren möchte, mehr als eine Instanz davon haben will. Bisher klang das immer so, ich hab da diese Einfachheit, weil ich eben nur einen Single-threaded Redis Server habe und der ist so superschnell, deshalb ist die Welt in Ordnung, was passiert, wenn ich das jetzt auf mehrere Systeme verteilen will?

Lucas Dohmen: Redis hat eine ganz einfache Master-Slave Replication, das heißt ich kann halt einem Knoten, also einer Redis-Instanz sagen, „Hey, du läufst so wie eine normale Instanz läuft“ und dann kann ich einer anderen Redis-Instanz sagen, „Bitte alles was diese Haupt-Redis-Instanz macht, das machst du auch“. Das heißt, wir haben hier eine exakte Kopie von dem, was in diesem Haupt-Redis passiert. Das kann man jetzt erstmal für verschiedene Sachen benutzen, zum Beispiel, um dann von diesem Follower oder Slave zu lesen, aber nicht zu schreiben, man schreibt nur auf den Master. Oder man braucht es halt als Hot- Backup, das heißt, wenn der Hauptserver abstürzt, dann können wir stattdessen einen der Follower verwenden.

Und dafür gibt es in Redis ein zusätzliches Programm, das sich Sentinel nennt. Das ist der Wächter, der wacht über verschiedene Redis-Instanzen. Und kann einen darüber informieren, wenn jetzt zum Beispiel eine bestimmte Instanz abgestürzt ist, dann könnte der einem über verschiedene Arten und Weise mitteilen, „Hey, da ist deine Redis-Instanz abgestürzt, vielleicht solltest du dich mal drum kümmern“. Aber der kann halt auch Automatic Failover machen. Das bedeutet, er sieht, „Ok, wir haben jetzt hier einen Master und fünf Slaves und jetzt ist der Master abgestürzt, ich bestimme jetzt einen von euch, dass er der neue Master wird. Und den anderen teile ich mit, hey, das ist jetzt euer Master.“ und so kann ich halt dafür sorgen, dass ich ein high availability System habe. Oder ein higher availability [System], je nachdem, wie man das sehen möchte. Das ist so der eine Weg. Das gibt es auch schon ne längere Zeit, also seit 2012 gibt es Sentinel als Feature von Redis.

Und seit 2015 gibt es zusätzlich auch noch Redis Cluster. Das ist die Möglichkeit, Redis zu sharden. Replication bedeutet ja, ich habe zwei Server, und der eine kopiert einfach alles, was der andere tut. Sharding bedeutet, ich habe mehr Daten, als ich auf einen Knoten packen kann. Das heißt, ich verteile die jetzt auf verschiedene Knoten. Und wenn ich jetzt mit diesem Cluster spreche, und ich sage, „Ich möchte gerne den und den Key haben“. Dann weiß der Cluster, welche von den verschiedenen Instanzen muss ich denn fragen, damit ich die Antwort kriege. Weil die anderen wüssten die Antwort ja nicht, weil die haben die Daten ja nicht. Und dafür gibt es Redis Cluster.

Stefan Tilkov: Wie ist die Qualität von dem Zeug? Also der von uns geschätzte Kyle Kingsbury – aphyr, können wir auch gerne verlinken – hat ja den Sentinel ziemlich auseinandergenommen damals, als das rauskam. Weißt du da den aktuellen Stand oder hast du da ne Meinung dazu? Wie zuverlässig das ist?

Lucas Dohmen: Ja, also es wurde seitdem jetzt nicht nochmal von Kyle Kingsbury selber getestet, und es ist auch nicht so, dass Redis als Test beispielsweise die Tools von Kyle Kingsbury benutzt. Das machen ja einige Datenbank Hersteller wie z.B. RethinkDB, als Integrationstest benutzen die halt das Tool von ihm, um zu gucken, wie läuft das denn jetzt so, hat diese Änderung jetzt was daran gemacht. Und das ist da nicht der Fall. Ich steh dem ein bisschen kritisch gegenüber. Also ich find Redis, wenn es als einzelner Knoten dasteht super, total klasse, ich hab damit noch nie schlechte Erfahrungen gemacht. Kyle Kingsbury hat ihn vor allem deswegen kritisiert, weil er viele von diesen Algorithmen sich selber ausgedacht hat und dabei auch scheinbar nicht soviel in bestehendes Research reingeschaut hat und deswegen viele Fehler gemacht hat, die viele Leute schon sehr, sehr viel früher gemacht haben, die hätten vermieden werden können. Das heißt, mein Vertrauen in seine Fähigkeit so eine Cluster- Lösung zu bauen ist nicht so hoch. Ich habe jetzt keine – also es gibt halt keinen momentanen – also soweit ich weiß, keine Untersuchung, ob das jetzt vielleicht besser geworden ist. Aber mein Vertrauen darin ist halt nicht so hoch. Weil es vorher halt nicht optimal gemacht wurde.

Stefan Tilkov: Mit seinem meinst du jetzt den Redis Autor.

Lucas Dohmen: Genau.

Stefan Tilkov: Ok. Gut. Das heißt es gibt diese Features, aber wir würden uns nicht aus dem Fenster lehnen und sagen, wir vertrauen denen unternehmenskritische Daten an. Sondern im Moment ist der Einsatzbereich eher für dieses Umfeld von Daten, die man vielleicht auch noch irgendwo anders hat, aber aus Performancegründen in diese superschnelle Datenbank reinpacken möchte. Wie einen Cache, wie du gesagt hast.

Lucas Dohmen: Genau. Und das ist auch einer der Gründe, warum ich meistens in Projekten, wo ich es bisher eingesetzt habe, auch von Anfang an gesagt habe, „Wir machen keine Persistenz“. Einfach, damit die Leute, die es benutzen, von Anfang an wissen, alles was ich da reinschreibe, könnte verschwinden.

Stefan Tilkov: Damit man die Erwartungshaltung gar nicht erst weckt, dass da irgendwas halten würde. Verstehe.

Lucas Dohmen: Genau. Und es ist einfach so, haben wir jetzt in dem aktuellen Projekt auch, irgendwann kommt die Sache so, „Ja, aber wenn wir das jetzt updaten, dann müssen wir den Redis Server wieder neustarten, dann sind ja die Daten weg, dann müssen wir von Neuem cachen“ – aber damit muss man klarkommen können. Das sollten nur Performance-Einbußen sein und nicht irgendwelche Daten die wirklich verloren gehen. Und das sehe ich halt gerade für die Sachen, wo ich es gerne für benutze – für Inter-Prozess-Kommunikation, für Caching und für solche Dinge – sehe ich das halt auch einfach als nicht so kritisch an. Man kann durchaus auch Redis als primäre Datenbank benutzen, ich kenne auch einige Leute, die das tun, ich persönlich bin da halt nicht so der Fan von.

Stefan Tilkov: Was ist das PL/SQL in der Redis-Welt? Also was benutze ich um Stored Procedures zu bauen? Wir waren ja bei Enterprise-Features?

Lucas Dohmen: (Lacht) Ja, also das vermisst man natürlich schnell, dann sagt man, „Wo ist mein PL/SQL“, und dann kann man auf Lua zurückgreifen. Lua ist eine Sprache, die speziell dafür designed wurde, embedded zu werden. Und das macht sie zu einer seltenen Art von Sprache. Es gibt eigentlich nur zwei große Sprachen, die wirklich dafür designed wurden. Das eine ist Lua und das andere ist Javascript. Javascript ist aber speziell designed, um in einem Browser embedded zu werden. Man hat es ja dann später auch einfach mal in node.js embedded, aber ursprünglich designed wurde es ja, um in einem Browser embedded zu werden.

Stefan Tilkov: Ich bin ein alter Mann, ich hätte noch Tcl erwähnt als Kandidat für sowas. Das kennt ja heute kein Mensch mehr deswegen –

Lucas Dohmen: (Lacht) Ich sag' ja nicht, dass es diese Art nicht gibt, aber sie ist selten. Und Lua ist eine Sprache, die auf jeden Fall nicht so viele unschöne Kanten hat wie Javascript, meiner Meinung nach. Ich bin jetzt kein Javascript- Hasser, ich schreibe jeden Tag Javascript. Aber es ist halt einfach so, da sind einige Sachen vielleicht einfach nicht so gut durchdacht gewesen. Und Lua ist da so ein bisschen sauberer designed. Aber wenn man Javascript kennt, dann kann man Lua relativ schnell lernen. Es kommt einem einfach viel bekannt vor, manchmal ist die Syntax so ein bisschen ungewöhnlich. Aber so eine ganz nette Sprache. Und eben diese Sprache wurde halt auch in Redis embedded, und da hat man jetzt die Möglichkeit zu sagen, „Leg jetzt bitte dieses Lua-Script in Redis“, und das funktioniert dann wieder auf dieselbe Art und Weise wie alles andere, es ist wieder ein Key-Value Pair. Nur, dass man in dem Fall den Key nicht selber bestimmt, sondern der ist die SHA-Summe von dem Lua-Script, den wir geschrieben haben. Das heißt, wenn ich sage, „Hier Redis, bitte speichere mal diesen Script ab“, dann gibt der einem eine SHA-Summe zurück und unter der kann ich die jetzt erreichen. Und dann kann ich sagen, „So, jetzt führe bitte den Script aus, der unter der SHA-Summe liegt“. Und da können wir jetzt erstmal grundsätzlich alles tun und lassen was wir wollen, ist ja Lua, kann jetzt erstmal sehr viele Sachen. Man kann auch Libraries benutzen, wenn man das möchte –

Stefan Tilkov: HTTP-Aufrufe machen…

Lucas Dohmen: (Lacht) man kann so einiges –

Stefan Tilkov: (Lacht) Uah, schauder –

Lucas Dohmen: Genau.

Stefan Tilkov: Klasse Idee. (Lacht)

Lucas Dohmen: Genau, aber da kommt direkt großes Warnzeichen, also zum einen ist sowas immer schon nicht so 'ne tolle Idee, aber zum anderen muss man da auch ganz doll aufpassen, weil ein Lua-Script grundsätzlich wieder eine Transaktion ist. Das heißt, während der Lua-Script läuft, laufen keine anderen Sachen. Das ist ja single-threaded. Das heißt, es wird gerade Lua gemacht, jetzt haben wir keine Zeit für was anderes. Das heißt, wenn ich da jetzt irgendwie ein Lua-Script ausführe, der 10 Sekunden dauert, kann ich in den 10 Sekunden meine Daten nicht getten und setten und expiren. Das geht halt einfach nicht, weil es ist jetzt besetzt. Das heißt, da ist halt die Empfehlung, was zu schreiben, was schnell passiert und was schnell durch ist.

Und Lua ist wirklich schnell – natürlich jetzt nicht so schnell wie C oder so aber es läuft sehr schnell, ich hatte damit jetzt nie Probleme. Man sollte das einfach nur beachten, man kann jetzt in diesem Lua-Script alle Befehle ausführen von Redis, die man möchte. Da hat man einfach ein Interface, da sagt man, „Hey, führ das aus, führ das aus“. Ich benutze es auch im aktuellen Projekt, das Lua- Scripting, um eine Transaktion auszuführen, wo ich halt im dritten Schritt 'ne Information brauche, die aus dem ersten Schritt kommt. Ne, so wie man das –

Stefan Tilkov: Ja, sonst hättest du ja auch die drei Befehle im Batch als Transaktion da hinschicken können –

Lucas Dohmen: Genau. Und meistens sind diese Lua-Script-Sachen so höchstens 20 Zeilen, mehr dann halt nicht, und dann reichts auch. Es ist halt nicht so leicht zum Debuggen wie man das vielleicht jetzt aus seiner Lieblingssprache kennt, man kann halt irgendwie Loggen, und damit kann man halt irgendwie Debuggen, wenn man das möchte. Aber es ist halt –

Stefan Tilkov: Gibt es noch andere Wege? Ich bin erstaunt.

Lucas Dohmen: (Lacht) Ja. Ein Thema für eine andere Folge.

Stefan Tilkov: Genau. Das heißt – also weil du vorhin gesagt hast, es wird praktisch die SHA-Summe über das Dinge genommen, das hängt also vom Content ab, nehme ich an. Also, wenn ich das Script ändere, bekomme ich 'nen neuen Key sozusagen für dieses Ding. Heißt das dann, dass ich ständig mein Programm anpassen muss? Wenn ich – ich bin gerade etwas irritiert. Wenn ich also eine neue Version dieses Lua-Scriptes baue, muss ich das aufrufende Programm anpassen weil das jetzt ein anderes –

Lucas Dohmen: Genau.

Stefan Tilkov: Finde ich das gut?

Lucas Dohmen: Am Anfang war ich entsetzt. Wie du, habe ich gedacht, „Was ist denn das?“. Aber eigentlich ist es 'ne super Lösung. Weil das, was ich aktuell mache, ist, wenn ich mein node.js Programm hochfahre, was ich als erstes mache, ist mein Lua, was ich in mein node.js Programm einfach mit eingecheckt habe ins Repository. Das nehme ich, speichere es auf dem Server und lass mir die SHA- Summe zurückgeben. Falls sie da schon sein sollte, ist das egal. Dann wird halt das Programm mit demselben Programm überschrieben, ich krieg die selbe SHA-Summe zurück. Falls aber der Redis irgendwann mal zwischendurch runtergefahren wurde und wieder hochgefahren wurde, wäre ja mein Programm weg. Weil, ich hab ja keine Persistence benutzt. Das heißt, da kann ich sicherstellen, „Ok, ich bin hochgefahren, der Redis ist da, alles ist gut“. Ich weiß, dass mein Script da ist, und den Namen von dem Script, also diese SHA-Summe von dem Script, die packe ich jetzt einfach in eine Variable und jedes Mal, wenn ich es aufrufe benutze ich einfach den Wert, der in der Variable steht. Und das finde ich eigentlich ganz elegant, weil auf diese Art und Weise kann ich halt immer sicherstellen, „Ok es ist wirklich da, und es ist in der Version die ich erwarte“, weil – die SHA-Summe lügt nicht.

Stefan Tilkov: Verstehe, ja, das klingt ganz überzeugend. Es muss aber doch auch schon irgendjemand anders auf die Idee gekommen sein, dass man anstatt von Lua doch vielleicht auch Javascript einbetten können müsste in die Redis-Engine? Oder nicht?

Lucas Dohmen: Stimmt (lacht). Aber aktuell ist nur Lua drin und mein Wissensstand ist auch, dass da nichts geplant ist, dass da noch was anderes reinkommt. Und das finde ich eigentlich auch gut so.

Stefan Tilkov: Das klingt so schön homomorph, weißt du, wenn du aus deinem node.js Programm, aus dem Javascript heraus das Javascript heraus in die Datenbank ein – du weißt was ich – völlig egal. Ok. Lua. Gut, was haben wir noch auf unserer Liste von Themen, über die wir reden wollten. Vielleicht ganz kurz – du hast mir noch zwei Projekte genannt, ich kann meine eigene Schrift nicht mehr lesen, was steht da – Ohm und Minuteman?

Lucas Dohmen: Genau, Ohm und Minuteman. Also, Redis – durch seine Einfachheit und durch dieses, dass man viele Sachen einfach von Hand machen muss, zieht einfach ein Publikum an, die das gerne machen. Die halt gerne eigene Sachen bauen und dabei etwas wollen, wo sie sich drauf verlassen können, dass es schnell ist und den Memory vernünftig verwaltet. Und da fallen mir jetzt irgendwie zwei Projekte ein, die das halt auf besonders interessante Art und Weise machen. Das eine ist Ohm. Das ist eine Ruby-Library, geschrieben von soveran. Und Ohm ist der ObjectHashMapper. Das heißt, das ist die Idee, wie eine ORM –

Stefan Tilkov: Ich bin begeistert.

Lucas Dohmen: Nur dass ich es nicht auf eine Relation mappe, sondern auf ein Hash. Hash, eine von den Datenstrukturen, die ich eben kurz vorgestellt habe. Ist also einfach die Idee, etwas zu bauen, was so ähnlich ist wie ActiveRecord. Nur dass es halt nicht auf eine SQL-Datenbank zugreift, sondern auf Redis. Und soveran benutzt, in all seinen Projekten als einzige Datenbank Redis. Er vertraut voll auf die Persistenz, und wir haben uns da ja schon öfters drüber unterhalten, wir sind da nicht einer Meinung, dass das halt so eine tolle Idee ist, aber ich finds immer wieder interessant, das zu sehen, weil er hat jetzt halt wirklich alles, was man so kennt. Man baut ein Modell, und sagt hier irgendwie ‚find_by name‘, dann brauch man nur einen Index anzulegen und Ohm sorgt dafür, dass dieser Index angelegt wird. Aber es ist kein Index, sondern halt wieder eine Redis-Datenstruktur.

Stefan Tilkov: Das hört sich ganz entsetzlich an. Aber ok.

Lucas Dohmen: (Lacht) Ja. Und es ist sehr wenig Code. Das ist, was daran noch erstaunlich ist.

Stefan Tilkov: Ok, gut. Minuteman?

Lucas Dohmen: Minuteman ist von elcuervo geschrieben. Das ist ein Programm, was einem einen Metrikserver zur Verfügung stellt. Damit kann man jetzt zum Beispiel User Tracking machen, so „track jedes mal, wenn ein User auf diese Website kommt, tu dies, tu das“, und nachher auch das auszuwerten. Und dabei greift er ganz tief in den Topf von Datentypen und Lua und was Redis einem so bietet. Ich hab mir den Code mal angeschaut und hab mit ihm drüber gequatscht, das ist einfach toll. Er benutzt da alles, von den Bitmaps und Sets und Hashes und hat das alles so gebaut, dass man extrem effizient, extrem schnell, einfach so Tracking-Informationen ablegen kann. Und für so einfach Use-Cases, wo man einfach nur wissen will, wieviele Leute kommen eigentlich auf meine Homepage, kann man das total klasse benutzen.

Stefan Tilkov: Das wiederum kann ich mir hervorragend vorstellen. Weil das ja auch perfekt zum Redis-Profil irgendwie passt, ne? Mit diesen Inkrement- Operationen und diesem schnellem Zählen und der Tatsache, dass das vielleicht nicht so unglaublich entsetzlich ist, wenn da vielleicht mal was verloren geht, das würde ich dann wahrscheinlich alle fünf Minuten mal aggregieren und dann woanders hin schreiben, wenn ich es langfristig aufbewahren will.

Lucas Dohmen: Genau.

Stefan Tilkov: Ok. Cool. Womit startet man, wenn man sich mit Redis beschäftigen will? Hast du da eine gute Startressource?

Lucas Dohmen: Mein Startvorschlag ist einfach auf redis.io zu gehen, da zu schauen wie man auf seiner Plattform Redis installiert, meistens im Paketmanager vorhanden. Einfach mal hochfahren, und dann sich auf der Commands Unterseite, die es da gibt, einfach mal angucken, was kann ich machen und einfach mal ausprobieren. Es gibt auf der Seite auch eine Sammlung von Artikeln, wo dann in verschiedener Tiefe die verschiedenen Aspekte beschrieben werden. Aber das schöne an Redis ist halt, um alles – um zu wissen, was alles Redis kann, braucht man nicht Jahre, wie jetzt bei irgendso einer SQL-Datenbank, sondern das hat man relativ schnell gesehen. Und dann guckt man sich halt die Befehle an, und dann kann man loslegen. Ein Buch würde ich da jetzt nicht unbedingt empfehlen. Also, ich habe mir das alles angeeignet über Ausprobieren und Seite lesen und Blogposts, die es da so gibt.

Stefan Tilkov: Alles klar. Gut, Lucas, das hat sehr viel Spaß gemacht, vielen Dank.

Lucas Dohmen: Ja, sehr gerne.

Stefan Tilkov: Und an unsere Hörer – danke fürs Zuhören, und bis zum nächsten Mal.

Lucas Dohmen: Ja, tschüss!

Stefan Tilkov: Ciao!