Redis, Kotlin und Node.js

Skidrow1988

Lt. Commander Pro
Registriert
Nov. 2014
Beiträge
1.067
Moin Leute,

ich gucke mir gerade Redis an und bin am überlegen einfach Mal zum lernen einen kleinen Chat zu schreiben. Wichtig, nicht produktiv und nicht öffentlich. Alles als Localhost.

Ich habe gelesen das viele Redis verwenden um eine Art Cache zu haben. Jetzt überlege ich, wie es Sinn ergibt vorzugehen und würde gerne eure Meinung hören/lesen.

Meine Gedankengang ist wie folgt. Ein User schreibt eine Nachricht und diese soll erst als "Broadcast" an alle im Raum verteilt werden. Soweit so gut. Nun würde ich gerne die letzten 50 Nachrichten mit Redis speichern um die Daten beim öffnen schneller verteilen zu können. Trotzdem würde ich die Daten persistent in einer MySQL Datenbank speichern. Ich weiß, viele sagen eine NoSQL würde mehr Sinn ergeben, ich habe aber da nicht die Erfahrung für. Da es mir hier gerade um das Kennenlernen von Redis geht, würde ich da gerne bleiben. Jetzt würde ich die Nachricht aber gerne editierbar machen. Dazu müsste ich der Nachricht eine eindeutige ID zuordnen, was ja eigentlich die MySQL Datenbank macht. Ich speichere aber erst nach dem Broadcast die Nachricht in der Datenbank und habe ja so lange keine ID. Ergibt es Sinn, eine UUID zu erzeugen und diese in Redis und in der MySQL Datenbank zu nutzen oder wie würdet ihr es machen?

Ich bin gespannt wie ihr es umsetzen würdet!
 
Ja richtig. Deshalb die Frage ob ich eine UUID mit node.js erzeuge und diese dann als ID auch in der DB nehme oder eben die eine Nachricht nachträglich in Redis mit einer ID versehe. Zusätzlich müsste ich die Nachricht ja auch wieder suchen können. Der Client würde die tatsächliche ID ja nicht kennen.
 
Wieso denn erst broadcasten und dann speichern? Der broadcast läuft doch sowieso async.
 
Man kann in Redis einstellen, dass die Daten persistiert werden. Für so einen Usecase wäre also gar keine relationale Datenbank erforderlich. Ich finde auch deinen Ansatz eines Client zu Client Broadcasts "falsch", da die Redis damit eigentlich "egal" ist.

Ich würde die Architektur so aufbauen:
  • Jeder Client hat eine Verbindung zu Redis
    • Besser: jeder Client hat eine Verbindung zu einem Backend Service
    • Begründung: Verbindung zu Redis setzt "volles Vertrauen" in den Client voraus -> nicht gegeben
  • Backend Service moderiert Zugriffe auf DB (lesend/schreibend für die Clients)
  • Redis speichert alle Nachrichten für alle Chats
  • Redis wird auf Persistierung gestellt
  • Redis erhält einen "Broadcast Channel", welcher alle Empfänger benachrichtigt, wenn es neue Einträge gibt (-> neue Nachricht pro Chat)
  • Backend Service hat ein "Broadcast Channel" (gRPC, SignalR, Socket.IO, Ntfy, ... je nachdem was du so nutzen möchtest) zu jedem Client
  • Client erhalten neue Nachrichten vom Backend Service gepusht und zeigen sie an
  • Entweder erzeugt der Backend Service die eindeutige ID oder der Client macht es gleich selbstständig.
    • Hinweis: du benötigst hier imme eine Rückmeldung an den Client, wie die ID denn nun ist. Damit würde ich regulär über Redis laufen (Neue Nachricht -> Backend Service -> ID erzeugen -> Redis -> Backend Service Neue Nachricht Broadcast -> Meldung an Client - Client prüft Nachricht und "ersetzt" die eigene, eben gesendete)

Vorteil:
  • Klare Zuständigkeiten
  • Sofortiger Datentransport (Chatnachricht) wenn Nachricht bei Redis eingeht
  • Erweiterbare Persistierung z.B. Redis wirklich nur als Cache und Persistierung über eine beliebige andere DB
  • System funktioniert prinzipiell von "überall" - also nicht nur im localen Netz
 
  • Gefällt mir
Reaktionen: dasBaum_CH und BeBur
Danke für die ausführliche Antwort. Werde ich mir mal zu Herzen nehmen und planen. Ich würde übrigens nicht Client zu Client arbeiten. Client -> Server -> Clients. Alles mit socket.io. Damit habe ich schon Erfahrung.
 
Der Weg über den Server ist für eine "Versuchsumgebung" schon okay. In der Praxis würde ich aber auch zusätzlich auf Client-zu-Client Kommunikation zusätzlich setzen.

Extrembeispiel: Kann mich dran erinnern, dass ich Ende der 90er mit ICQ Dateien im LAN rumverschickt habe. Aber gibt ja auch keinen Grund, dass Chats erst mal zu einem US-Server müssen und wieder zurück um empfangen zu werden.

Wegen der ID: Aus meiner Sicht sollte der Client die Message-ID (nicht unbedingt ein Datenbank-Primary-Key) festlegen, denn wenn die Kommunikation zwischen Client und Server mal Probleme macht, und der Client potentiell mehrmals die gleiche Message an den Server senden möchte (im Worst Case bleibt ja nur die Bestätigung für den Erhalt des Server aus), dann ist der Server eben auch robust genug mehrmals die selbe Nachricht empfangen zu haben. Und der Empfänger, der könnte die Nachricht auf unterschiedlichen Wegen empfangen, direkt vom Sender-Client, oder über den Umweg des Servers, was halt schneller wäre, und er ließe sich dann auch nicht "verwirren".
 
tollertyp schrieb:
Der Weg über den Server ist für eine "Versuchsumgebung" schon okay
Ich würde argumentieren eine Peer to Peer Verbindung für reguläres Messaging ist bestenfalls für eine Versuchsumgebung okay. Es hat schlicht viele Nachteile.

Dazu kommt erhöhte Komplexität um Duplikate zu erkennen. Außerdem kann man nicht sicherstellen, dass die Daten wirklich zur Persistierung angekommen sind.

tollertyp schrieb:
Chats erst mal zu einem US-Server müssen und wieder zurück um empfangen zu werden.
Latenz ist egal. Ob es 40 ms innerhalb Deutschland oder 500 ms für Hin- und Rücktransfer USA ist für Nachrichtentransfer unerheblich.

tollertyp schrieb:
ich Ende der 90er mit ICQ Dateien im LAN rumverschickt habe
Datentransfer ist ein anderer Use Case als klassisches Messaging.
 
  • Gefällt mir
Reaktionen: tollertyp
Duplikate kann man problemlos bei eindeutigen Message-IDs erkennen. Und wieso sollte man diese Dinge nicht sicherstellen können? Wieso sollte man nicht sicherstellen können, dass die Daten zur Persistierung angekommen sind? Die zusätzliche Kommunikation direkt zwischen den Clients sorgt ja dafür, dass selbst bei Serverausfall die Kommunikation noch möglich ist, und der Client kann problemlos später all seine Nachrichten noch an den Server senden lassen und den Erhalt entsprechend "quittieren" lassen.

Und Latenz: 500 ms vs 6 ms im LAN sind schon ein Unterschied.

Edit:
Wobei ein Szenario natürlich dafür spricht, alle Kommunikation über den Server zu führen: Wenn sich ein Nutzer gleichzeitig an mehreren Clients anmelden kann. Und - das muss ich zugeben - das ist schon etwas, was ich heutzutage von einer Chat-Plattform erwarte.

Also ja, die Variante ist für mich also auch okay.
 
tollertyp schrieb:
ie zusätzliche Kommunikation direkt zwischen den Clients sorgt ja dafür, dass selbst bei Serverausfall die Kommunikation noch möglich ist
Das ist richtig, aber das wäre ein ganz anderer Use Case.

tollertyp schrieb:
Duplikate kann man problemlos bei eindeutigen Message-IDs erkennen
Daten vom Client darf man nicht vertrauen. Wir haben wohl nur die Message-ID, aber im Zweifelsfall ist das gefälscht. Nicht so easy.

tollertyp schrieb:
Wieso sollte man nicht sicherstellen können, dass die Daten zur Persistierung angekommen sind?
Du kannst schlichtweg nicht auf einfache Weise sicherstellen, dass die Daten von Client zu Server transferiert werden können. Wenn das also "nie" geht (Server gesperrt, kein Internet, ...), dann erhalten die User zwar untereinander Nachrichten, im Nachgang sind sie aber nie am Server und beim Neustart der App einfach gelöscht. Das erzeugt sehr unzufriedene User.

Der Fehler ist dann auch kaum zu diagnostizieren, da manim Zweifelsfall auf die User Endgeräte keinen Zugriff hat.

Denken wir an ein P2P System (Chat) und eine zentrale Persistierung, dann müsste man auch ein relativ komplexe Synchronisation implementieren. Dann ist der Server nicht mehr der Master sondern er kann eben Inhalte haben, die "veraltet" sein können. Schwierig.

Diese Anforderung ist aber gegeben, da der TE gerne "Nachrichten editieren" möchte.

Im Kern würde ich ein "P2P" System nur in Erwägung ziehen, wenn es explizit Teil der Anforderung ist. Dezentrale Systeme sind deutlich komplexer als zentrale. Von einem großen Problem, "Broadcast", "Client Detection", "Public IP Resolution und solche Erfordernisse für ein P2P System noch gar nicht gesprochen.

tollertyp schrieb:
Und Latenz: 500 ms vs 6 ms im LAN sind schon ein Unterschied.
Wieso ist das relevant? Ob du ne Nachricht in 6 oder 600 ms bekommst, nimmt der Mensch doch gar nicht war. Zumal das alles ein rein theoretisches Problem ist, der Server steht bei der Umgebung "in der Nähe".
 
andy_0 schrieb:
Daten vom Client darf man nicht vertrauen. Wir haben wohl nur die Message-ID, aber im Zweifelsfall ist das gefälscht. Nicht so easy.
Wie soll das konkrete Fälschen hier aussehen? Soll sich der Client als anderer Client ausgeben?

andy_0 schrieb:
Wieso ist das relevant? Ob du ne Nachricht in 6 oder 600 ms bekommst, nimmt der Mensch doch gar nicht war.
Also wenn ich in einem Raum bin, und eine Nachricht an jemanden sende, dann nehme ich einen Unterschied von 594 ms wahr. Und ich behaupte, ich bin nicht besonders gut in Bezug auf Reaktionszeiten.
 
Eins kann man festhalten, so einfach ist das Thema scheinbar nicht. Ich muss mir mal grundlegende Gedanken darum machen.
 
  • Gefällt mir
Reaktionen: tollertyp
Also ich widerspreche dir auch gar nicht grundsätzlich, ist auch wirklich Neugierde dabei. Manchmal sieht man Dinge nicht, die andere sehen - gerade in Bezug auf Angriffsszenarien.
 
Skidrow1988 schrieb:
Eins kann man festhalten, so einfach ist das Thema scheinbar nicht.
Selbst "einfache" Themen können in der Informatik schnell beliebig komplex werden. Deswegen ist es wichtig, vernünftige Grenzen zu setzen (was möchte ich machen, was geht einfach, was ist unnötig komplex) und evtl. Lücken als "gewusst, aber erst mal nicht betrachtet" abzuhaken. Dafür muss man sich aber Gedanken gemacht haben, was für Lücken evtl. da sein können.

tollertyp schrieb:
Wie soll das konkrete Fälschen hier aussehen? Soll sich der Client als anderer Client ausgeben?
Ein Client könnte beliebig viele Nachrichten schicken (message bombing). Ein Client könnte Nachrichten an andere Client schicken, die mit ihm kein Chat gewünscht haben (spamming). Ein Client könnte eine Nachricht beliebig häufig schicken. Ein Client könnte versuchen, sich als ein anderer auszugeben (identity theft). Ein Client könnte versuchen, dem anderen Client eine Nachricht unterzuschieben (Form von identity theft). Ein Client könnte versuchen, eine von sich oder einem anderen Client geschickte Nachricht zu duplizieren und mit anderen Inhalt zu füllen (und es dann im Server zu persistieren). Ein Client könnte versuchen Nachrichten rückzudatieren (Nachrichten die es im Verlauf niemals gab). Ein Client könnte versuchen, eine beliebige Nachricht zu modifzieren. Ein Client könnte versuchen, eine manipulierte Nachricht zu verschicken, die ein anderen Client schädigt (viele verschiedene Formen denkbar).

Ich denke die Liste ist sicherlich nicht ausführlich.

Kann man all das "einfach so" mit einem Server-Backend verhindern? Nein. Aber man kann doch einiges verhindern und vieles andere deutlich erschweren.

Jetzt sprechen wir nur von absichtlichen Angriffen. Je komplexer die Logik, je aufwändiger wird der Code und je mehr Fehler werden vorhanden sein.
 
  • Gefällt mir
Reaktionen: Skidrow1988
andy_0 schrieb:
Ein Client könnte beliebig viele Nachrichten schicken (message bombing).
Sorry, aber ab hier habe ich schon nicht weitergelesen. Könnte man Fragen auch einfach mal in dem Kontext beantworten, in dem sie gestellt sind?
"Wir haben wohl nur die Message-ID" darum geht es, war deine Aussage, und du erzählst von Gott und der Welt...
 

Ähnliche Themen

S
Antworten
2
Aufrufe
1.326
S
Zurück
Oben