Aufbau eines Benachrichtigungssystems [geschlossen]


170

Ich bin am Anfang des Aufbaus eines Benachrichtigungssystems im Facebook-Stil für unsere Seite (Social-Gaming-Typ) und recherchiere jetzt, wie ein solches System am besten gestaltet werden kann. Ich bin nicht daran interessiert, wie ich Benachrichtigungen an den Benutzer oder ähnliches senden kann (vorerst sogar). Ich recherchiere, wie man das System auf dem Server erstellt (wie man Benachrichtigungen speichert, wo man sie speichert, wie man sie abruft usw.).

Also ... einige Anforderungen, die wir haben:

  • In Spitzenzeiten haben wir ungefähr 1k gleichzeitig angemeldete Benutzer (und viele weitere Gäste, aber sie spielen hier keine Rolle, da sie keine Benachrichtigungen haben), die viele Ereignisse generieren
  • Es wird verschiedene Arten von Benachrichtigungen geben (Benutzer A hat Sie als Freund hinzugefügt, Benutzer B hat Ihr Profil kommentiert, Benutzer C hat Ihr Bild gefallen, Benutzer D hat Sie in Spiel X geschlagen, ...)
  • Die meisten Ereignisse generieren 1 Benachrichtigung für 1 Benutzer (Benutzer X hat Ihr Bild gefallen), aber es gibt Fälle, in denen ein Ereignis viele Benachrichtigungen generiert (z. B. der Geburtstag von Benutzer Y).
  • Benachrichtigungen sollten zusammengefasst werden. Wenn zum Beispiel vier verschiedene Benutzer ein Bild mögen, sollte der Besitzer dieses Bildes eine Benachrichtigung erhalten, die besagt, dass vier Benutzern das Bild gefallen hat und nicht vier separate Benachrichtigungen (genau wie FB).

OK, ich dachte also, ich sollte eine Art Warteschlange erstellen, in der ich Ereignisse speichern würde, wenn sie eintreten. Dann hätte ich einen Hintergrundjob ( Gearman ?), Der sich diese Warteschlange ansieht und Benachrichtigungen basierend auf diesen Ereignissen generiert. Dieser Job speichert dann Benachrichtigungen in der Datenbank für jeden Benutzer (wenn also ein Ereignis 10 Benutzer betrifft, gibt es 10 separate Benachrichtigungen). Wenn der Benutzer dann eine Seite mit der Liste der Benachrichtigungen öffnet, liest ich alle diese Benachrichtigungen für ihn (wir denken daran, diese auf 100 neueste Benachrichtigungen zu beschränken) und gruppiert sie und zeigt sie schließlich an.

Dinge, die mir bei diesem Ansatz Sorgen machen:

  • komplex wie die Hölle :)
  • Ist die Datenbank hier der beste Speicher (wir verwenden MySQL) oder sollte ich etwas anderes verwenden (Redis scheint auch gut zu passen)?
  • Was soll ich als Benachrichtigung speichern? Benutzer-ID, Benutzer-ID, die das Ereignis ausgelöst hat, Art des Ereignisses (damit ich sie gruppieren und den entsprechenden Text anzeigen kann), aber dann weiß ich nicht, wie die tatsächlichen Daten der Benachrichtigung gespeichert werden sollen (z. B. URL und Titel des Bildes, das wurde gemocht). Soll ich diese Informationen beim Generieren der Benachrichtigung nur "backen" oder die ID des betroffenen Datensatzes (Bild, Profil, ...) speichern und die Informationen beim Anzeigen der Benachrichtigung aus der Datenbank ziehen?
  • Die Leistung sollte hier in Ordnung sein, auch wenn ich beim Anzeigen der Benachrichtigungsseite 100 Benachrichtigungen im laufenden Betrieb verarbeiten muss
  • Mögliches Leistungsproblem bei jeder Anfrage, da ich dem Benutzer die Anzahl der ungelesenen Benachrichtigungen anzeigen müsste (was für sich genommen ein Problem sein könnte, da ich Benachrichtigungen zusammenfassen würde). Dies könnte jedoch vermieden werden, wenn ich die Ansicht von Benachrichtigungen (wo sie gruppiert sind) im Hintergrund und nicht im laufenden Betrieb generiere

Was halten Sie von meinem Lösungsvorschlag und meinen Bedenken? Bitte kommentieren Sie, wenn Sie der Meinung sind, dass ich noch etwas erwähnen sollte, das hier relevant wäre.

Oh, wir verwenden PHP für unsere Seite, aber das sollte hier kein großer Faktor sein, denke ich.


Wie viel Zeit haben Sie gebraucht, um dieses Benachrichtigungssystem als Ein-Mann-Anstrengung aufzubauen? Ich möchte nur eine Schätzung haben, um die Zeitpläne entsprechend zu erstellen.
Shaharyar

@ Shaharyar Ich denke, es hängt von der Komplexität des Benachrichtigungssystems ab.
Tyan

Ich habe dasselbe System mit MySQL verwendet, um ein prioritätsbasiertes Benachrichtigungssystem zu erstellen. Das Gute ist, dass es auf einige tausend Benutzer skaliert werden kann. Wenn es mehr geht, explodiert es, insbesondere mit Android und GCM. Ich würde gerne Alternativen zu MySQL wie Redis, RabbitMQ, Kafka kennen, die natürlich eine Nachrichtenwarteschlange aufweisen, eine Art Funktionalität.
Ankit Marothi

Antworten:


168

Bei einer Benachrichtigung handelt es sich um etwas (Objekt = Ereignis, Freundschaft ..), das von jemandem (Schauspieler) geändert (Verb = hinzugefügt, angefordert ..) und dem Benutzer (Betreff) gemeldet wird. Hier ist eine normalisierte Datenstruktur (obwohl ich MongoDB verwendet habe). Sie müssen bestimmte Benutzer über Änderungen informieren. Es handelt sich also um Benachrichtigungen pro Benutzer. Wenn also 100 Benutzer beteiligt sind, generieren Sie 100 Benachrichtigungen.

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
║notification ║      ║notification_object║      ║notification_change ║
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
║ID           ║—1:n—→║ID                 ║—1:n—→║ID                  ║
║userID       ║      ║notificationID     ║      ║notificationObjectID║
╚═════════════╝      ║object             ║      ║verb                ║
                     ╚═══════════════════╝      ║actor               ║
                                                ╚════════════════════╝

(Fügen Sie Zeitfelder hinzu, wo Sie es für richtig halten.)

Dies dient im Wesentlichen zum Gruppieren von Änderungen pro Objekt, sodass Sie sagen können, dass Sie 3 Freundschaftsanfragen haben. Eine Gruppierung pro Schauspieler ist nützlich, sodass Sie sagen können, dass "Benutzer James Bond Änderungen in Ihrem Bett vorgenommen hat". Dies gibt Ihnen auch die Möglichkeit, Benachrichtigungen nach Belieben zu übersetzen und zu zählen.

Da es sich bei dem Objekt jedoch nur um eine ID handelt, müssten Sie alle zusätzlichen Informationen zu dem gewünschten Objekt mit separaten Aufrufen abrufen, es sei denn, das Objekt ändert sich tatsächlich und Sie möchten diesen Verlauf anzeigen (z. B. "Benutzer hat den Titel des Ereignisses in ... geändert". ")

Da Benachrichtigungen für Benutzer auf der Site nahezu in Echtzeit erfolgen, würde ich sie mit dem Client nodejs + websockets verknüpfen, wobei PHP das Update für alle Listener auf nodejs überträgt, wenn Änderungen hinzugefügt werden.


1
notification_object.object identifiziert den Änderungstyp wie eine Zeichenfolge "Freundschaft". Der tatsächliche Verweis auf das geänderte Objekt mit seinen zusätzlichen Daten, über die ich
spreche,

2
Dies mag eine dumme Frage sein, aber was tun Sie mit dieser Einstellung, wenn der Benutzer die Benachrichtigung gesehen oder darauf reagiert hat? Entfernen Sie es einfach aus der Datenbank oder verwenden Sie nur Datumsangaben, um festzustellen, ob sich der Benutzer seit der Erstellung der Benachrichtigung angemeldet hat?
Jeffery Mills

4
Ich weiß, dass dieses Thema schon ziemlich alt ist, aber ich bin ein bisschen verwirrt über den ersten Tisch. Was genau ist der Zweck dieses Tisches? Was ist der Vorteil einer separaten Tabelle gegenüber dem Einfügen der Benutzer-ID in die Tabelle "notification_object"? Mit anderen Worten, wann erstellen Sie einen neuen Eintrag in der Benachrichtigung und wann fügen Sie einfach ein Objekt hinzu und ändern eine vorhandene Benachrichtigung mit dieser Struktur?
Bas Goossen

3
@JefferyMills Sie könnten ein Statusfeld wie is_notification_readin der notificationTabelle haben und es entsprechend markieren, wenn es ist unread, readoder deleted.
Kevin

2
Ich habe mich auch bemüht, einige Aspekte dieser Lösung zu verstehen, und eine separate Frage dazu gestellt: dba.stackexchange.com/questions/99401/…
user45623

27

Dies ist wirklich eine abstrakte Frage, also müssen wir sie wohl nur diskutieren, anstatt darauf hinzuweisen, was Sie tun oder nicht tun sollten.

Folgendes denke ich über Ihre Bedenken:

  • Ja, ein Benachrichtigungssystem ist komplex, aber nicht so höllisch. Sie können viele verschiedene Ansätze zur Modellierung und Implementierung solcher Systeme verfolgen, und diese können von mittlerer bis hoher Komplexität reichen.

  • Pesonally versuche ich immer, Sachen datenbankgesteuert zu machen. Warum? Weil ich garantieren kann, dass ich die volle Kontrolle über alles habe, was vor sich geht - aber das bin nur ich. Sie können die Kontrolle ohne einen datenbankgesteuerten Ansatz haben. Vertrau mir, du wirst die Kontrolle über diesen Fall haben wollen.

  • Lassen Sie mich einen realen Fall für Sie veranschaulichen, damit Sie irgendwo anfangen können. Im vergangenen Jahr habe ich ein Benachrichtigungssystem in einer Art sozialem Netzwerk modelliert und implementiert (natürlich nicht wie Facebook). Wie habe ich dort Benachrichtigungen gespeichert? Ich hatte eine notificationsTabelle, in der ich die generator_user_id(die ID des Benutzers, der die Benachrichtigung generiert), die target_user_id(irgendwie offensichtlich, nicht wahr?), Die notification_type_id(die auf eine andere Tabelle mit Benachrichtigungstypen verwies) und alle aufbewahrte das notwendige Zeug, mit dem wir unsere Tabellen füllen müssen (Zeitstempel, Flaggen usw.). Meine notification_typesTabelle hatte früher eine Beziehung zu einer notification_templatesTabelle, in der bestimmte Vorlagen für jede Art von Benachrichtigung gespeichert waren. Zum Beispiel hatte ich einen POST_REPLYTyp, der eine Art Vorlage hatte {USER} HAS REPLIED ONE OF YOUR #POSTS. Von dort habe ich gerade die behandelt{}als Variable und #als Referenzlink;

  • Ja, die Leistung sollte und muss in Ordnung sein. Wenn Sie an Benachrichtigungen denken, denken Sie an Server, die von Kopf bis Fuß pushen. Entweder wenn Sie es mit Ajax-Anfragen machen oder was auch immer, müssen Sie sich um die Leistung sorgen. Aber ich denke, das ist ein zweites Mal.

Das Modell, das ich entworfen habe, ist natürlich nicht das einzige, dem Sie folgen können, auch nicht das beste. Ich hoffe, meine Antwort folgt Ihnen zumindest in die richtige Richtung.


Warum hätte ich keine Kontrolle über einen anderen Datenspeicher?
Jan Hančič

Nun, das habe ich nicht gesagt. Was ich gesagt habe ist, dass ich die Datenkontrolle nur mit einem datenbankgesteuerten Ansatz garantieren kann; aber das bin nur ich. Ich werde das umformulieren.
Daniel Ribeiro

@DanielRibeiro Die Platzhalter ({...}) in der Benachrichtigungsvorlage müssen Daten von Platzhaltern aus den verschiedenen Tabellen in der Datenbank für die verschiedenen Arten von Benachrichtigungen ersetzen. Beispiel: Eine Vorlage lautet "{Benutzer} hat Ihr Foto gefallen.", Eine andere Vorlage lautet "Ihr {Seitenname} hat ein neues" Gefällt mir ". Usw. {Seitenname} und {Benutzer} sowie andere Platzhalter werden aus der unterschiedlichen Datenbanktabelle zugeordnet. Was sollte also das Schema sein, um den Platzhalterwert dynamisch abzurufen?
Ashish Shukla

DanielRibeiro, wie Sie Platzhalter ersetzt haben, wie von @Ashish Shukla,
Shantaram Tupe

@AshishShukla haben Sie Platzhalter verwendet oder ersetzt, und wie?
Shantaram Tupe

8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Dies scheint eine gute Antwort zu sein, anstatt zwei Sammlungen zu haben. Sie können nach Benutzername, Objekt und isRead abfragen, um neue Ereignisse abzurufen (z. B. 3 ausstehende Freundschaftsanfragen, 4 gestellte Fragen usw.).

Lassen Sie mich wissen, wenn es ein Problem mit diesem Schema gibt.


3
Die Top-Antwort verwendete eine normalisierte Datenstruktur, was bedeutet, dass keine Redundanzen in den Tabellen vorhanden sind. Tut Ihre Antwort das?
Aaron Hall

4

Ich persönlich verstehe das Diagramm für die akzeptierte Antwort nicht sehr gut. Daher werde ich ein Datenbankdiagramm hinzufügen, das auf dem basiert, was ich aus der akzeptierten Antwort und anderen Seiten lernen kann.

Geben Sie hier die Bildbeschreibung ein

Verbesserungen werden gut aufgenommen.


Scheint, als würde sich message_template in der NotificationType-Tabelle befinden. Es scheint auch so, als ob sich die main_url in der Benachrichtigungstabelle befindet. Dann könnten Sie die Notification_Message-Tabelle entfernen. Können Sie erklären, warum Sie die NotificationMessage-Tabelle alleine haben?
Jeff Ryan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.