Verwendung von Redis für Echtzeit-Messanwendungen

Roshan Kumar ist Senior Product Manager bei Redis Labs .

Die Messung ist nicht nur ein einfaches Zählproblem. Das Messen wird oft mit dem Messen verwechselt, aber es ist normalerweise mehr als das. Die Messung umfasst zwar das Messen, ist jedoch ein fortlaufender Prozess, normalerweise mit dem Ziel, die Nutzung oder den Fluss einer Ressource im Laufe der Zeit zu regulieren. Moderne Anwendungen umfassen die Messung auf viele verschiedene Arten, von der Zählung von Personen, Objekten oder Ereignissen bis hin zur Regulierung der Nutzung, Kontrolle des Zugriffs und Zuweisung von Kapazität.

Messlösungen müssen im Allgemeinen große Datenmengen verarbeiten und gleichzeitig die strengen Leistungsanforderungen erfüllen. Abhängig vom Umfang der Lösung kann das Zählen und Messen Tausende, wenn nicht Millionen von Aktualisierungen einer Datenbank pro Sekunde umfassen. Die Hauptanforderungen an eine Datenbank zur Unterstützung einer solchen Lösung sind ein hoher Durchsatz für Schreibvorgänge und eine geringe Latenzzeit (unter Millisekunden) für Antworten.

Redis, die Open-Source-In-Memory-Datenbankplattform, bietet beide Vorteile und ist gleichzeitig kostengünstig, da nur minimale Hardwareressourcen verwendet werden. In diesem Artikel werden wir bestimmte Funktionen von Redis untersuchen, die es zu einer guten Wahl für Messlösungen machen, und wie wir Redis für diesen Zweck verwenden können. Aber zuerst schauen wir uns einige der häufigsten Anwendungen der Messung an.

Gängige Messanwendungen

Die Messung ist in jeder Anwendung erforderlich, in der die Nutzung einer Ressource im Laufe der Zeit gemessen werden muss. Hier sind vier gängige Szenarien:

  1. Verbrauchsbasierte Preismodelle . Im Gegensatz zu einmaligen oder abonnementbasierten Zahlungsmodellen können Verbraucher bei verbrauchsabhängigen Preismodellen nur für die tatsächliche Nutzung bezahlen. Verbraucher genießen mehr Flexibilität, Freiheit und Kosteneinsparungen, während Anbieter eine größere Kundenbindung erzielen.

    Die Implementierung solcher Modelle kann schwierig sein. Manchmal muss das Messsystem viele Nutzungselemente und viele Metriken in einem einzigen Plan verfolgen. Beispielsweise kann ein Cloud-Anbieter unterschiedliche Preisstufen für CPU-Zyklen, Speicher, Durchsatz, Anzahl der Knoten oder Nutzungsdauer eines Dienstes festlegen. Ein Telekommunikationsunternehmen kann unterschiedliche zulässige Verbrauchswerte für Minuten, Daten oder Text festlegen. Die Messlösung muss je nach Art der verbrauchsabhängigen Preisgestaltung das Begrenzen, Aufladen oder Erweitern von Diensten erzwingen.

  2. Einschränkung der Ressourcennutzung . Jeder Dienst im Internet kann durch übermäßige Nutzung missbraucht werden, es sei denn, dieser Dienst ist preislich begrenzt. Beliebte Dienste wie die Google AdWords-API und die Twitter Stream-API enthalten aus diesem Grund Ratenbeschränkungen. Einige extreme Fälle von Missbrauch führen zu Denial-of-Service (DoS). Um Missbrauch zu verhindern, müssen Dienste und Lösungen, auf die über das Internet zugegriffen werden kann, mit angemessenen Regeln zur Ratenbegrenzung ausgestattet sein. Selbst einfache Authentifizierungs- und Anmeldeseiten müssen die Anzahl der Wiederholungsversuche für ein bestimmtes Zeitintervall begrenzen.

    Ein weiteres Beispiel, bei dem eine Einschränkung der Ressourcennutzung erforderlich wird, besteht darin, dass bei Änderung der Geschäftsanforderungen Legacy-Systeme stärker belastet werden, als sie unterstützen können. Durch die Begrenzung der Anrufe auf die Legacy-Systeme können sich Unternehmen an die wachsende Nachfrage anpassen, ohne ihre Legacy-Systeme ersetzen zu müssen.

    Neben der Verhinderung von Missbrauch und der Reduzierung der Last hilft eine gute Ratenbegrenzung auch bei der Verwaltung von Bursty-Verkehrsszenarien. Beispielsweise kann eine API, die eine Methode zur Begrenzung der Brute-Force-Rate erzwingt, 1000 Anrufe pro Stunde zulassen. Ohne eine Richtlinie zur Gestaltung des Datenverkehrs kann ein Client die API in den ersten Sekunden jeder Stunde 1000 Mal aufrufen und möglicherweise die von der Infrastruktur unterstützte Unterstützung überschreiten. Beliebte Ratenbegrenzungsalgorithmen wie Token Bucket und Leaky Bucket verhindern Bursts, indem sie die Anrufe nicht nur begrenzen, sondern auch über die Zeit verteilen.

  3. Ressourcenverteilung . Überlastung und Verzögerungen sind häufige Szenarien in Anwendungen, die sich mit Paketrouting, Jobverwaltung, Verkehrsstaus, Massenkontrolle, Social Media-Nachrichten, Datenerfassung usw. befassen. Warteschlangenmodelle bieten verschiedene Optionen zum Verwalten der Warteschlangengröße basierend auf der Ankunfts- und Abflugrate. Die Implementierung dieser Modelle in großem Maßstab ist jedoch nicht einfach.

    Rückstand und Überlastung sind ständige Sorgen beim Umgang mit schnellen Datenströmen. Clevere Designer müssen akzeptable Warteschlangenlängenbeschränkungen definieren und dabei sowohl die Überwachung der Warteschlangenleistung als auch das dynamische Routing basierend auf den Warteschlangengrößen berücksichtigen.

  4. Skalieren für Entscheidungen in Echtzeit . E-Commerce-Websites, Spieleanwendungen, soziale Medien und mobile Apps ziehen täglich Millionen von Nutzern an. Da mehr Augäpfel zu höheren Einnahmen führen, ist es für das Geschäft von entscheidender Bedeutung, die Besucher und ihre Aktionen genau zu zählen. Das Zählen ist in ähnlicher Weise nützlich für Anwendungsfälle wie Fehlerwiederholungen, Problemeskalation, Verhinderung von DDoS-Angriffen, Verkehrsprofilierung, Ressourcenzuweisung bei Bedarf und Betrugsbekämpfung.

Herausforderungen beim Messdesign

Lösungsarchitekten müssen beim Erstellen einer Messanwendung viele Parameter berücksichtigen, beginnend mit diesen vier:

  1. Designkomplexität. Das Zählen, Verfolgen und Regulieren von Datenmengen - insbesondere wenn sie mit hoher Geschwindigkeit ankommen - ist eine entmutigende Aufgabe. Lösungsarchitekten können die Messung auf Anwendungsebene mithilfe von Programmiersprachenstrukturen durchführen. Ein solches Design ist jedoch nicht widerstandsfähig gegen Fehler oder Datenverlust. Herkömmliche festplattenbasierte Datenbanken sind robust und versprechen ein hohes Maß an Datenbeständigkeit bei Ausfällen. Sie bieten jedoch nicht nur nicht die erforderliche Leistung, sondern erhöhen auch die Komplexität ohne die richtigen Datenstrukturen und Tools zur Implementierung der Messung.
  2. Latenz. Die Messung umfasst in der Regel zahlreiche, ständige Aktualisierungen der Anzahl. Die Lese- / Schreiblatenz von Netzwerk und Festplatte summiert sich bei großen Zahlen. Dies könnte dazu führen, dass ein riesiger Datenstau entsteht, der zu weiteren Verzögerungen führt. Die andere Quelle der Latenz ist ein Programmdesign, das die Messdaten aus einer Datenbank in den Hauptspeicher des Programms lädt und nach Aktualisierung des Zählers in die Datenbank zurückschreibt.
  3. Parallelität und Konsistenz. Das Entwickeln einer Lösung zum Zählen von Millionen und Milliarden von Elementen kann komplex werden, wenn Ereignisse in verschiedenen Regionen erfasst werden und alle an einem Ort zusammenlaufen müssen. Datenkonsistenz wird zu einem Problem, wenn viele Prozesse oder Threads gleichzeitig dieselbe Anzahl aktualisieren. Sperrtechniken vermeiden Konsistenzprobleme und sorgen für Konsistenz auf Transaktionsebene, verlangsamen jedoch die Lösung.
  4. Haltbarkeit. Die Messung wirkt sich auf die Umsatzzahlen aus, was bedeutet, dass kurzlebige Datenbanken hinsichtlich der Haltbarkeit nicht ideal sind. Ein In-Memory-Datenspeicher mit Haltbarkeitsoptionen ist die perfekte Wahl.

Verwenden von Redis für Messanwendungen

In den folgenden Abschnitten werden wir untersuchen, wie Redis zum Zählen und Messen von Lösungen verwendet wird. Redis verfügt über integrierte Datenstrukturen, atomare Befehle und TTL-Funktionen (Time-to-Live), mit denen Anwendungsfälle für die Leistungsmessung verwendet werden können. Redis läuft auf einem einzelnen Thread. Daher werden alle Datenbankaktualisierungen serialisiert, sodass Redis als sperrfreier Datenspeicher fungieren kann. Dies vereinfacht das Anwendungsdesign, da Entwickler keine Anstrengungen zur Synchronisierung der Threads oder zur Implementierung von Sperrmechanismen für die Datenkonsistenz unternehmen müssen.  

Atomic Redis-Befehle zum Zählen

Redis bietet Befehle zum Inkrementieren von Werten, ohne dass diese in den Hauptspeicher der Anwendung gelesen werden müssen.

Befehl Beschreibung
INCR Schlüssel Erhöhen Sie den ganzzahligen Wert eines Schlüssels um eins
INCRBY Tasteninkrement Erhöhen Sie den ganzzahligen Wert eines Schlüssels um die angegebene Zahl
INCRBYFLOAT Tasteninkrement Erhöhen Sie den Float-Wert eines Schlüssels um den angegebenen Betrag
DECR Schlüssel Verringern Sie den ganzzahligen Wert eines Schlüssels um eins
DECRBY Schlüsseldekrement Verringern Sie den ganzzahligen Wert eines Schlüssels um die angegebene Zahl
HINCRBY Schlüsselfeldinkrement Erhöhen Sie den ganzzahligen Wert eines Hash-Feldes um die angegebene Zahl
HINCRBYFLOAT Schlüsselfeldinkrement Erhöhen Sie den Float-Wert eines Hash-Felds um den angegebenen Betrag

Redis speichert Ganzzahlen als 64-Bit-Ganzzahl mit Vorzeichen 10. Daher ist die maximale Grenze für eine ganze Zahl eine sehr große Zahl: 263 - 1 = 9.223.372.036.854.775.807.

Integrierte Lebensdauer (Time-to-Live, TTL) auf Redis-Tasten

Einer der häufigsten Anwendungsfälle bei der Messung besteht darin, die Nutzung anhand der Zeit zu verfolgen und die Ressourcen nach Ablauf der Zeit zu begrenzen. In Redis kann ein Wert für die Lebensdauer der Schlüssel festgelegt werden. Redis deaktiviert die Schlüssel nach einer festgelegten Zeitüberschreitung automatisch. In der folgenden Tabelle sind verschiedene Methoden zum Ablaufen von Schlüsseln aufgeführt.

Befehl Beschreibung
EXPIRE Schlüsselsekunden Stellen Sie die Lebensdauer eines Schlüssels in Sekunden ein
EXPIREAT Schlüsselzeitstempel Legen Sie den Ablauf für einen Schlüssel als Unix-Zeitstempel fest
PEXPIRE Schlüssel Millisekunden Stellen Sie die Lebensdauer eines Schlüssels in Millisekunden ein
PEXPIREAT Schlüsselzeitstempel Legen Sie den Ablauf für einen Schlüssel als UNIX-Zeitstempel in Millisekunden fest
SET Schlüsselwert [EX Sekunden] [PX Millisekunden] Setzen Sie den Zeichenfolgenwert zusammen mit der optionalen Lebensdauer auf einen Schlüssel

Die folgenden Meldungen geben Ihnen die Lebensdauer der Tasten in Sekunden und Millisekunden an.

Befehl Beschreibung
TTL Schlüssel Holen Sie sich die Zeit, um für einen Schlüssel zu leben
PTTL Schlüssel Nehmen Sie sich die Zeit, um in Millisekunden nach einem Schlüssel zu leben

Redis Datenstrukturen und Befehle für effizientes Zählen

Redis ist bekannt für seine Datenstrukturen wie Listen, Sets, sortierte Sets, Hashes und Hyperloglogs. Viele weitere können über die Redis-Modul-API hinzugefügt werden.

Redis Labs

Redis-Datenstrukturen verfügen über integrierte Befehle, die für die Ausführung mit maximaler Effizienz im Speicher optimiert sind (genau dort, wo die Daten gespeichert sind). Einige Datenstrukturen helfen Ihnen dabei, viel mehr zu erreichen als nur Objekte zu zählen. Beispielsweise garantiert die Set-Datenstruktur die Eindeutigkeit aller Elemente.

Sortiertes Set geht noch einen Schritt weiter, indem sichergestellt wird, dass dem Set nur eindeutige Elemente hinzugefügt werden, und Sie die Elemente anhand einer Punktzahl sortieren können. Wenn Sie Ihre Elemente beispielsweise nach Zeit in einer Sorted Set-Datenstruktur sortieren, erhalten Sie eine Zeitreihendatenbank. Mithilfe von Redis-Befehlen können Sie Ihre Elemente in einer bestimmten Reihenfolge abrufen oder Elemente löschen, die Sie nicht mehr benötigen.

Hyperloglog ist eine weitere spezielle Datenstruktur, die die Anzahl von Millionen eindeutiger Elemente schätzt, ohne die Objekte selbst speichern oder den Speicher beeinflussen zu müssen.

Datenstruktur Befehl Beschreibung
Liste LLEN Schlüssel Holen Sie sich die Länge einer Liste
einstellen SCARD Schlüssel Ermitteln Sie die Anzahl der Mitglieder in einem Satz (Kardinalität).
Sortiertes Set ZCARD Schlüssel Ermitteln Sie die Anzahl der Mitglieder in einem sortierten Satz
Sortiertes Set ZLEXCOUNT Schlüssel min max Zählen Sie die Anzahl der Mitglieder in einem sortierten Satz zwischen einem bestimmten lexikografischen Bereich
Hash HLEN Schlüssel Ermitteln Sie die Anzahl der Felder in einem Hash
Hyperloglog PFCOUNT Schlüssel Ermitteln Sie die ungefähre Kardinalität des von der Hyperloglog-Datenstruktur beobachteten Satzes
Bitmap BITCOUNT Taste [Start Ende] Zählt gesetzte Bits in einer Zeichenfolge

Redis-Persistenz und In-Memory-Replikation

Bei der Messung von Anwendungsfällen wie Zahlungen werden Informationen gespeichert und aktualisiert, die für Unternehmen von entscheidender Bedeutung sind. Datenverlust wirkt sich direkt auf den Umsatz aus. Es kann auch Abrechnungsaufzeichnungen zerstören, die häufig eine Compliance- oder Governance-Anforderung darstellen.

Sie können die Konsistenz und Haltbarkeit in Redis basierend auf Ihren Datenanforderungen optimieren. Wenn Sie einen dauerhaften Nachweis für Ihre Messdaten benötigen, können Sie durch die Persistenzfunktionen von Redis eine lange Lebensdauer erreichen. Redis unterstützt AOF (Nur-Anhängen-Datei), mit der Schreibbefehle sofort auf die Festplatte kopiert werden, und Snapshots, mit denen die zu einem bestimmten Zeitpunkt vorhandenen Daten auf die Festplatte geschrieben werden.

Eingebaute, sperrenfreie Redis-Architektur

Die Redis-Verarbeitung erfolgt mit einem Thread. Dies stellt die Datenintegrität sicher, da alle Schreibbefehle automatisch serialisiert werden. Diese Architektur entlastet Entwickler und Architekten von der Last, Threads in einer Multithread-Umgebung zu synchronisieren.

Im Fall einer beliebten mobilen Consumer-Anwendung können Tausende und manchmal Millionen von Benutzern gleichzeitig auf die Anwendung zugreifen. Angenommen, die Anwendung misst die verwendete Zeit und zwei oder mehr Benutzer können gleichzeitig Minuten teilen. Die parallelen Threads können dasselbe Objekt aktualisieren, ohne die zusätzliche Belastung durch die Gewährleistung der Datenintegrität zu verursachen. Dies reduziert die Komplexität des Anwendungsdesigns und gewährleistet gleichzeitig Geschwindigkeit und Effizienz.

Redis-Messbeispielimplementierungen

Schauen wir uns den Beispielcode an. Einige der folgenden Szenarien würden sehr komplexe Implementierungen erfordern, wenn die verwendete Datenbank nicht Redis wäre.

Blockieren mehrerer Anmeldeversuche

Um den unbefugten Zugriff auf Konten zu verhindern, blockieren Websites Benutzer manchmal daran, innerhalb eines festgelegten Zeitraums mehrere Anmeldeversuche durchzuführen. In diesem Beispiel beschränken wir die Benutzer daran, mehr als drei Anmeldeversuche in einer Stunde mithilfe einfacher Key-Time-to-Live-Funktionen durchzuführen.

Der Schlüssel für die Anzahl der Anmeldeversuche:

user_login_attempts:

Schritte:

Ermitteln Sie die aktuelle Anzahl der Versuche:

GET user_login_attempts:

Wenn null, setzen Sie den Schlüssel mit der Ablaufzeit in Sekunden (1 Stunde = 3600 Sekunden):

SET user_login_attempts: 1 3600

Wenn nicht null und wenn die Anzahl größer als 3 ist, werfen Sie einen Fehler:

Wenn dies nicht null ist und die Anzahl kleiner oder gleich 3 ist, erhöhen Sie die Anzahl:

INCR user_login_attempts:

Bei einem erfolgreichen Anmeldeversuch kann der Schlüssel wie folgt gelöscht werden:

DEL user_login_attempts:

Zahlen Sie wenn sie hinausgehen

Die Redis Hash-Datenstruktur bietet einfache Befehle zum Verfolgen der Nutzung und Abrechnung. In diesem Beispiel nehmen wir an, dass jeder Kunde seine Rechnungsdaten in einem Hash gespeichert hat, wie unten gezeigt:

Kundenabrechnung:

     Verwendung

     Kosten

     .

     .

Angenommen, jede Einheit kostet zwei Cent und der Benutzer verbraucht 20 Einheiten. Die Befehle zum Aktualisieren der Verwendung und Abrechnung sind:

hincrby Kunde: Nutzung 20

hincrbyfloat Kunde: Kosten .40

Wie Sie vielleicht bemerkt haben, kann Ihre Anwendung die Informationen in der Datenbank aktualisieren, ohne dass sie die Daten aus der Datenbank in ihren eigenen Speicher laden muss. Darüber hinaus können Sie ein einzelnes Feld eines Hash-Objekts ändern, ohne das gesamte Objekt zu lesen.

Bitte beachten Sie: In diesem Beispiel wird gezeigt, wie die Befehle hincrbyund verwendet hincrbyfloatwerden. In einem guten Design vermeiden Sie das Speichern redundanter Informationen wie Nutzung und Kosten.