Redis – die schnelle Schlüssel-Wert-Datenbank

RedisRedis ist eine Schlüssel-Wert-Datenbank, und gehört somit zu den nicht-relationalen NoSQL-Datenbanken. Da Redis die Datensätze im Arbeitsspeicher und nicht auf der Festplatte des Servers speichert, ist sie deutlich schneller als herkömmliche Datenbanken.

Schlüssel Wert
Name Redis
Kategorie Datenbank
Typ Schlüssel-Wert
Lizenz BSD-Lizenz

Redis kann man sich als zweispaltige Tabelle vorstellen. In der ersten Splate befinden sich die Schlüsselnamen, in der zweiten die Werte.

Daten werden in Redis als Schlüssel und zugehörige Werte gespeicherte, und auch ausschließlich so abgefragt. Das heißt, es ist möglich den Wert zu Schlüssel x abzufragen, aber beispielsweise nicht möglich, alle Schlüsselnamen abzufragen, welche den Wert y enthalten. Auch Abfragen wie „gib mir alle Werte, die mit Hallo anfangen“ sind in Redis nicht möglich.

Einsatzzwecke #

Aufgrund dieser Gegebenheiten eignet sich Redis gut für einfache Datenstrukturen, bei denen die Inhalte möglichst schnell gespeichert und abgefragt werden sollen, wozu z.B. die Sitzungs-Cookies einer Webanwendung zählen (im englischen Sessions genannt). Für komplexere Stukturen ist Redis hingegen weniger geeignet, da es hierfür deutlich funktionsreichere Alternativen wie MongoDB gibt.

Man könnte zwar theoretisch auch komplexere Datenstrukturen mit Redis realisieren, und die Abfrage eines einzelnen Wertes mit Redis wäre sicherlich schneller als mit anderen Datenbanken. Wenn man aber bedenkt, dass man bei komplexen Strukturen auf andere Schlüssel verweisen müsste und somit mehr als eine einzige Abfrage notwendig wäre, so gleicht sich der Geschwindigkeits-Vorteil auch wieder aus. Daher würde es in den meisten Fällen weder aus Performance- noch aus Funktions-Gründen einen Grund dafür geben, Redis als Datenbank für komplexe Datenstukturen zu verwenden.

Eine Kombination aus Redis mit einer anderen Datenbank ist jedoch durchaus vorstellbar, und wenn man sowohl Funktionsvielfalt als auch Geschwindigkeit braucht sicherlich die ideale Lösung. So könnte beispielsweise ein Online-Shop die Produkte, Rechnungen und Benutzerkonten in einer MongoDB-Datenbank speichern, während die Sitzungs-Cookies in Redis gespeichert würden.

Datentypen #

Im Gegensatz zu anderen Schlüssel-Wert-Datenbanken wie Memcached können in Redis nicht nur einfache Zeichenketten (englisch strings) gespeichert werden, sondern auch erweiterte Datentypen, die wiederum Zeichenketten beinhalten, nämlich lists, sets, sorted sets und hashes.

Im folgenden findest du eine Übersicht mit allen fünf Datentypen. Um die gezeigten Redis-Befehle selbst auszutesten, kannst du diese Online-Konsole verwenden.

Strings #

Der Datentyp Strings ist der Basis-Datentyp von Redis, in dem alle möglichen Zeichenketten wie Texte, serialisierte Objekte, aber auch Bilder oder andere Dateien gespeichert werden können. Die maximale Größe eines Wertes beträgt dabei 512 Megabyte (kurz MB), was in etwa einem halben Gigabyte (kurz GB) entspricht.

Möchte man größere Dateien speichern, so müsste man die Datei auf mehrere Werte wie datei:1, datei:2 und datei:3 aufteilen, und von einem anderen Wert aus auf die einzelnen Werte verweisen, genauer gesagt die Länge der verwendeten Werte angeben, woraufhin man dann alle einzelnen Werte nacheinander abfragt.

Neben den Redis-Befehlen SET und GET, womit man einen String speichert und ausliest, kennt Redis noch weitere Befehle wie APPEND, womit ein String um weitere Zeichen erweitert wird, oder STRLEN, womit man die Länge eines Strings ermitteln kann.

SET test "Hallo Welt!"                  # OK
GET test                                # "Hallo Welt!"
APPEND test " Das ist nur ein Test."    # (integer) 33
GET test                                # "Hallo Welt! Das ist nur ein Test."
STRLEN test                             # (integer) 33

Lists #

Der Datentyp Lists ist eine Liste bestehend aus einzelnen Strings. Es ist sowohl möglich, einen neuen Eintrag am Anfang, als auch am Ende der Liste hinzuzufügen. Dazu verwendet man die Befehle LPUSH für den Anfang bzw. Links, und RPUSH für das Ende bzw. rechts.

Jeder Eintrag einer Liste hat dabei eine Index-Nummer. Der aller erste bekommt die 0, der zweite je nachdem ob er am Anfang oder am Ende eingefügt wurde eine -1 oder 1, und so weiter. Mittels LINDEX bekommt man den Inhalt eines Listen-Eintrags angezeigt, und mit LSET kann man ihn bearbeiten.

Um eine Abfolge von Einträgen abzufragen, steht zudem auch der Befehl LRANGE zur Verfügung, der als Parameter die zu beginnende und endente Index-Nummer übergeben bekommt.

LPUSH meineliste "Der erste Eintrag"     # (integer) 1
LPUSH meineliste "Der zweite Eintrag"    # (integer) 2
RPUSH meineliste "Der dritte Eintrag"    # (integer) 3
RPUSH meineliste "Der vierte Eintrag"    # (integer) 4
LINDEX meineliste 0                      # "Der zweite Eintrag"
LINDEX meineliste 1                      # "Der erste Eintrag"
LINDEX meineliste -1                     # "Der vierte Eintrag"
LINDEX meineliste -2                     # "Der dritte Eintrag"
LSET meineliste 1 "Test"                 # OK
LINDEX meineliste 1                      # "Test"
LRANGE meineliste -2 1
# 1) "Der dritte Eintrag"
# 2) "Der vierte Eintrag"
# 3) "Der erste Eintrag"

Sets #

Der Datentyp Sets ist eine unsortierte Liste von Strings. In einer solchen Liste kann jeder Eintrag nur einmal vorkommen, versucht man ihn erneut hinzuzufügen, so wird angezeigt, dass er bereits vorhanden ist.

Mit dem Befehl SADD fügt man einen Eintrag zu einer Liste hinzu, und mittels SMEMBERS listet man diese auf. Um zu prüfen, ob ein Eintrag bereits in einer Liste vorhanden ist, kann man den Befehl SIDMEMBER verwenden.

SADD sets "erster Eintrag"      # (integer) 1
SADD sets "zweiter Eintrag"     # (integer) 1
SADD sets "dritter Eintrag"     # (integer) 1
SCARD sets                      # (integer) 3
SMEMBERS sets
# 1) "zweiter Eintrag"
# 2) "erster Eintrag"
# 3) "dritter Eintrag"
SISMEMBER sets "bla bla bla"    # (integer) 0
SISMEMBER sets "erster Eintrag" # (integer) 1

Sorted Sets #

Der Datentyp Sorted Sets ist ebenfalls eine Liste in der jeder Eintrag nur einmal vorkommen darf, unterscheidet sich aber von Sets durch die Möglichkeit, die Einträge anhand von Punkten zu sortieren. Die Einträge werden dabei von den wenigsten zu den meisten Punkten sortiert, und es darf auch mehrmals die gleiche Punktzahl vergeben werden.

Das hinzufügen von Einträgen geschieht mit dem Befehl ZADD, wobei die vergebenen Punkte vor dem eigentlichem Inhalt erwartet werden.

ZRANGE listet die Einträge anschließend auf, dabei gibt man neben den Namen der Liste auch an, bei welchem Listen-Eintrag begonnen und bei welchem geendet werden soll. Der erste Eintrag hat dabei die Nummer 0, will man die Einträge bis zum eine Anzeigen, so muss man -1 für den letzten Eintrag angeben. Übergibt man zusätzlich WITHSCORES, so werden auch die vergebenen Punkte angezeigt. Siehe dazu das folgende Beispiel:

ZADD meineliste 1 "Apfel"            # (integer) 1
ZADD meineliste 2 "Birne"            # (integer) 1
ZADD meineliste 20 "Banane"          # (integer) 1
ZADD meineliste 5 "Kirsche"          # (integer) 1
ZRANGE meineliste 0 -1 WITHSCORES
# 1) "Apfel"
# 2) "1"
# 3) "Birne"
# 4) "2"
# 5) "Kirsche"
# 6) "5"
# 7) "Banane"
# 8) "20"

Hashes

Der Datentyp Hashes besteht aus einzelnen Feldern und zugehörigen Inhalten. Er ist daher vergleichbar mit einem Objekt in einer Programmiersprache wie JavaScript, nur dass in Hashes – ebenso wie bei allen anderen Redis-Datentypen – alle Inhalte als Zeichenketten gespeichert werden. Die Inhalte eines Hashes lassen sich wie folgt darstellen:

{
    benutzername: 'nodecode', 
    passwort: 'extremgeheim', 
    alter: '99'
}

Während sich mit HSET nur jeweils ein Feld ändern lässt, können mit dem Befehl HMSET auch mehrere Felder gleichzeitig festgelegt werden. Ebenso kann mit HGET ein einzelnes Feld, und mit HGETALL alle Felder abgefragt werden.

HMSET benutzer:100 benutzername nodecode passwort extremgeheim alter 99     # OK
HGETALL benutzer:100
# 1) "benutzername"
# 2) "nodecode"
# 3) "passwort"
# 4) "extremgeheim"
# 5) "alter"
# 6) "99"
HSET benutzer:100 passwort 123456                                           # (integer) 0
redis 127.0.0.1:6379> HGETALL benutzer:100
# 1) "benutzername"
# 2) "nodecode"
# 3) "passwort"
# 4) "123456"
# 5) "alter"
# 6) "99""
HGET benutzer:100 passwort                                                  # "123456"

Abschließend ist noch darauf hinzuweisen, dass in diesem Abschnitt nur die Grundlagen zu den einzelnen Datentypen und nur die wichtigsten deren Befehle beschrieben wurden. In der offiziellen Dokumentation findet sich darüber hinaus genaueres zu den Datentypen, sowie eine Liste mit allen Befehlen.

Datensicherung #

Redis speichert alle Daten im Arbreitsspeicher. Würde der Server nun herunterfahren oder abstürzten, so wäre der Arbeisspeicher bei einem erneuten Start gelöscht, und somit auch alle Daten in Redis. Um dies zu verhindern, fertigt Redis regelmäßig eine Kopie aller Daten auf der Festplatte an.

Die Standardkonfiguration dazu sieht folgendermaßen aus:

save 900 1
save 300 10
save 60 10000

Diese führt dazu, dass nach 900 Sekunden (15 Minuten) gespeichert wird, wenn mindestens ein Schlüssel geändert wurde, nach 300 Sekunden (5 Minuten) bei mindestens 10 geänderten Schlüsseln, und nach 60 Sekunden (eine Minute) bei mindestens 10.000 Änderungen.

appendonly #

Wenn man eine besonders hohe Datensicherheit haben möchte, so könnte man die Konfiguration in save 1 1 ändern, woraufhin die Daten jede Sekunde gesichert werden, wenn mindestens ein Schlüssel geändert wurde. Dennoch würden bei einem Ausfall des Servers die Änderungen bis zur letzen Sicherung verloren gehen, was in diesem Fall im Zeitrahmen von maximal einer Sekunde wäre.

Für eine maximale Datensicherheit stellt Redis den sogenannten Appendonly-Modus zur Verfügung, welcher sich in der Kofigurationsdatei mit appendonly yes aktivieren lässt. Ist Appendonly aktiviert, werden alle Änderungen sofort in eine separate Datei (appendonly.aof) geschrieben, aus der bei einem Neustart dann alle Schlüssel rekonstruiert werden.

Zwar werden für den Appendonly-Modus die regulären Speicherkopien nicht benötigt, da Redis bei einem Neustart alle Schlüssel aus der Datei appendonly.aof rekonstruiert und dabei die regulären Speicherkopien ignoriert, dennoch kann aber beides zusammen aktiviert werden.

Redis unter Node.js verwenden #

Um Redis unter Node.js zu verwenden, muss neben Redis selbst auch das gleichnamige Node.js-Modul installiert werden. Um letzteres zu erreichen, tippt man in die Konsole folgende Anweisung ein:

npm install redis

Dannach kann man die Redis-Schnitstelle in eine Node.js-Anwendung laden:

var redis = require("redis");

Sich anschließend über die Funktion redis.createClient() mit den Server verbinden:

var client = redis.createClient();

Und mit entsprechenden Funktionen wie client.set() auf die Redis-Datenbank zugreifen:

client.set("schlüssel", "wert", redis.print);

Im Falle von set wird dabei als erster Parameter der Schlüsselname, als zweiter er zugehörige Wert, und als letztes die aufgerufene Callback-Funktion übergeben. Die Callback-Funktion bekommt als erstes den Fehler (sofern vorhanden) übergeben, und als zweites die Antwort von Redis. Mit redis.print steht eine Funktion zur Verfügung, welche die übergebenen Daten in die Konsole schreibt.

hiredis #

Das Node.js-Modul redis verwendet normalerweise einen in JavaScript geschriebenen Redis-Parser. Für eine bessere Performance empfiehlt es sich, zusätzlich das Modul hiredis zu installieren (mit npm install hiredis), welches auf den offiziellen in C geschrieben Redis-Client (hiredis) zurückgreift. Ist hiredis installiert, so erkennt redis das, und verwendet den Parser von hiredis anstelle des eigenen JavaScript-Parsers.

Es wird jedoch darauf hingewiesen, hiredis nach einem Upgrade von Node.js ebenfalls zu aktualisieren, da es sonst zu Fehler zwischen Node.js selbst und nativen Modulen wie hiredis kommen kann.

VN:F [1.9.22_1171]
Bewertung: 5.0/5 (4 Bewertungen)
Redis – die schnelle Schlüssel-Wert-Datenbank, 5.0 out of 5 based on 4 ratings
Regelmäßige Beiträge über Node.js

nodecodeAbonniere den kostenlosen NodeCode-Newsletter, und bleibe auf dem laufenden über neue Beiträge zum Thema Node.js. Darunter:

  • Informationen und Neuigkeiten rund um Node.js und zugehörigen Modulen
  • Vorstellung von interessanten Frameworks und Bibliotheken
  • Anleitungen und Tutorials zu Node.js und weiterführenden Technologien
  • Sowie vieles mehr...

schon 3 Kommentare gehe zum kommentieren

  1. Peter /

    Wenn redis nur zum schnellen Abspeichern von Schlüsselpaaren gedacht ist, wieso sollte ich nicht statdessen einfach ein lokales JSON verwenden? Das ist doch ebenso schnell und flüchtig, oder? Welchen Vorteil habe ich durch die zusätzliche Verwendung von redis?

    1. NodeCode / Beitrags-Autor

      Redis hat gegenüber einem lokalen JavaScript-Objekt zwei Vorteile: Zum einen könnende Werte zu Schlüsseln nicht nur abgespeichert und abgefragt werden, sondern es stehen viele spezielle Datentypen und Befehle bereit, die über reine Variablen hinaus gehen. Einige davon wurde ja im Artikel vorgestellt. Und zum anderen ermöglicht ein Datenbanksystem wie Redis es, dass mehrere Anwendungen gleichzeitig auf die gleiche Datenbank zugreifen können. Eine Variable wäre hingegen nur in einem einzigen Programm verfügbar.

      Eine Redis-Datenbank ist übrigens nicht unbedingt flüchtig, sondern wird sogar per Standardeinstellung regelmäßig auf der Festplatte gesichert, wie im Absatz Datensicherung beschrieben. Das wäre dann genau genommen ein dritter Vorteil.

      Eine eigenständige Datenbankanwendung wie Redis sollte immer dann verwendet werden, wenn mindestens einer dieser drei genannten Vorteile (spezielle Datentypen und Befehle, mehrere Anwendungen/Benutzer, nicht flüchtige Datensätze) von Bedeutung ist.

      1. Peter /

        Danke, das macht es gleich verständlicher.

        Ihr habt hier wirklich eine super Seite. :)

hinterlasse einen Kommentar