it-swarm.com.de

Implementieren des Aktivitätsstroms in einem sozialen Netzwerk

Ich entwickle mein eigenes soziales Netzwerk und habe im Web keine Beispiele für die Implementierung des Streams von Benutzeraktionen gefunden. Wie kann ich beispielsweise Aktionen für jeden Benutzer filtern? Wie speichere ich die Aktionsereignisse? Welches Daten- und Objektmodell kann ich für den Aktionsstrom und für die Aktionen selbst verwenden?

132
Nicolò Martini

Zusammenfassung : Für ungefähr 1 Million aktive Benutzer und 150 Millionen gespeicherte Aktivitäten halte ich es einfach:

  • Verwenden Sie eine relationale Datenbank zum Speichern eindeutiger Aktivitäten (1 Datensatz pro Aktivität/"Ereignis"). Stellen Sie die Datensätze so kompakt wie möglich zusammen. Strukturieren Sie diese so, dass Sie schnell einen Stapel von Aktivitäten nach Aktivitäts-ID oder mithilfe einer Reihe von Freund-IDs mit zeitlichen Einschränkungen abrufen können.
  • Veröffentlichen Sie die Aktivitäts-IDs bei jeder Erstellung eines Aktivitätsdatensatzes in Redis, und fügen Sie die ID zu einer "Aktivitäts-Stream" -Liste für jeden Benutzer hinzu, der ein Freund/Abonnent ist, der die Aktivität sehen soll.

Fragen Sie Redis ab, um den Aktivitätsdatenstrom für einen beliebigen Benutzer abzurufen, und greifen Sie dann bei Bedarf auf die zugehörigen Daten aus der Datenbank zu. Greifen Sie auf die Abfrage der Datenbank nach Zeit zurück, wenn der Benutzer in der Zeit weit zurückblättern muss (sofern Sie dies überhaupt anbieten).


Ich benutze eine einfache alte MySQL-Tabelle, um ungefähr 15 Millionen Aktivitäten abzuwickeln.

Es sieht ungefähr so ​​aus:

id             
user_id       (int)
activity_type (tinyint)
source_id     (int)  
parent_id     (int)
parent_type   (tinyint)
time          (datetime but a smaller type like int would be better) 

activity_type Gibt die Art der Aktivität an, source_id Gibt den Datensatz an, auf den sich die Aktivität bezieht. Wenn der Aktivitätstyp also "hinzugefügter Favorit" bedeutet, dann weiß ich, dass sich die source_id auf die ID eines Lieblingsdatensatzes bezieht.

Die parent_id/parent_type Sind nützlich für meine App - sie sagen mir, womit die Aktivität zusammenhängt. Wenn ein Buch favorisiert wurde, würde mir parent_id/parent_type mitteilen, dass sich die Aktivität auf ein Buch (Typ) mit einem bestimmten Primärschlüssel (ID) bezieht.

Ich indexiere auf (user_id, time) Und frage nach Aktivitäten, die user_id IN (...friends...) AND time > some-cutoff-point sind. Es könnte eine gute Idee sein, die ID zu löschen und einen anderen Clustered-Index zu wählen - damit habe ich noch nicht experimentiert.

Ziemlich einfaches Zeug, aber es funktioniert, es ist einfach und es ist einfach, damit zu arbeiten, wenn sich Ihre Bedürfnisse ändern. Wenn Sie MySQL nicht verwenden, können Sie möglicherweise auch einen besseren Index erstellen.


Um schneller auf die neuesten Aktivitäten zugreifen zu können, habe ich mit Redis experimentiert. Redis speichert alle seine Daten im Arbeitsspeicher, sodass Sie nicht alle Ihre Aktivitäten dort ablegen können, aber Sie könnten genug für die meisten häufig auf Ihrer Website verwendeten Bildschirme speichern. Die letzten 100 für jeden Benutzer oder so ähnlich. Mit Redis in der Mischung könnte es so funktionieren:

  • Erstellen Sie Ihren MySQL-Aktivitätsdatensatz
  • Übertragen Sie für jeden Freund des Benutzers, der die Aktivität erstellt hat, die ID in die Aktivitätsliste in Redis.
  • Kürzen Sie jede Liste auf die letzten X Elemente

Redis ist schnell und bietet die Möglichkeit, Befehle über eine Verbindung zu übertragen. Das Auslagern einer Aktivität auf 1000 Freunde dauert also Millisekunden.

Eine ausführlichere Erklärung dessen, worüber ich spreche, finden Sie in Redis 'Twitter-Beispiel: http://redis.io/topics/Twitter-clone

Update Februar 2011 Ich habe zur Zeit 50 Millionen aktive Aktivitäten und ich habe nichts geändert. Eine nette Sache, etwas Ähnliches zu tun, ist, dass es kompakte, kleine Reihen verwendet. Ich plane einige Änderungen vorzunehmen, die viel mehr Aktivitäten und mehr Abfragen dieser Aktivitäten beinhalten würden, und ich werde auf jeden Fall Redis verwenden, um die Dinge schnell zu halten. Ich benutze Redis in anderen Bereichen und es funktioniert wirklich gut für bestimmte Arten von Problemen.

Update Juli 2014 Wir haben bis zu 700.000 aktive Benutzer pro Monat. In den letzten Jahren habe ich Redis (wie in der Aufzählung beschrieben) zum Speichern der letzten 1000 Aktivitäts-IDs für jeden Benutzer verwendet. Es gibt normalerweise ungefähr 100 Millionen Aktivitätsdatensätze im System und sie sind immer noch in MySQL gespeichert und haben immer noch das gleiche Layout. Mit diesen Datensätzen können wir weniger Redis-Speicher entlasten, sie dienen als Aufzeichnung von Aktivitätsdaten und wir verwenden sie, wenn Benutzer rechtzeitig weiterblättern müssen, um etwas zu finden.

Dies war keine clevere oder besonders interessante Lösung, hat mir aber gute Dienste geleistet.

233
casey

Dies ist meine Implementierung eines Aktivitätsstroms mit MySQL. Es gibt drei Klassen: Activity, ActivityFeed, Subscriber.

Aktivität stellt einen Aktivitätseintrag dar und seine Tabelle sieht folgendermaßen aus:

id
subject_id
object_id
type
verb
data
time

Subject_id ist die ID des Objekts, das die Aktion ausführt, object_id Die ID des Objekts, das die Aktion empfängt. type und verb beschreiben die Aktion selbst (wenn ein Benutzer beispielsweise einen Kommentar zu einem Artikel hinzufügt, handelt es sich um "Kommentar" bzw. "Erstellt"), enthalten Daten zusätzliche Daten, um Vermeiden Sie Verknüpfungen (z. B. können darin der Vor- und Nachname des Betreffs, der Titel des Artikels und die URL, der Kommentartext usw. enthalten sein).

Jede Aktivität gehört zu einer oder mehreren ActivityFeeds und ist durch eine Tabelle verbunden, die folgendermaßen aussieht:

feed_name
activity_id

In meiner Anwendung habe ich einen Feed für jeden Benutzer und einen Feed für jedes Element (normalerweise Blog-Artikel), aber diese können beliebig sein.

Ein Abonnent ist normalerweise ein Benutzer Ihrer Site, es kann sich aber auch um ein beliebiges Objekt in Ihrem Objektmodell handeln (z. B. könnte ein Artikel für die feed_action seines Erstellers abonniert werden).

Jeder Abonnent gehört zu einer oder mehreren ActivityFeeds und ist wie oben durch eine Verknüpfungstabelle dieser Art verbunden:

feed_name
subscriber_id
reason

Im Feld reason wird erläutert, warum der Abonnent den Feed abonniert hat. Wenn ein Benutzer beispielsweise ein Lesezeichen für einen Blogeintrag erstellt, ist der Grund "Lesezeichen". Dies hilft mir später beim Filtern von Aktionen für Benachrichtigungen an die Benutzer.

Um die Aktivität für einen Abonnenten abzurufen, führe ich einen einfachen Join der drei Tabellen durch. Der Beitritt ist schnell, da ich dank einer WHERE - Bedingung, die wie folgt aussieht, nur wenige Aktivitäten auswähle: time > some hours. Ich vermeide andere Verknüpfungen dank des Datenfelds in der Aktivitätstabelle.

Weitere Erklärung zum Feld reason. Wenn ich zum Beispiel Aktionen für E-Mail-Benachrichtigungen an den Benutzer filtern möchte und der Benutzer einen Blogeintrag mit einem Lesezeichen versehen hat (und daher den Post-Feed mit dem Grund "Lesezeichen" abonniert), möchte ich nicht, dass der Benutzer dies erhält E-Mail-Benachrichtigungen zu Aktionen für dieses Element. Wenn er den Beitrag kommentiert (und daher den Beitrags-Feed mit dem Grund "Kommentar" abonniert), möchte ich, dass er benachrichtigt wird, wenn andere Benutzer dem gleichen Beitrag Kommentare hinzufügen. Das Feld "Grund" hilft mir bei dieser Unterscheidung (ich habe es über eine ActivityFilter-Klasse implementiert), zusammen mit den Benachrichtigungseinstellungen des Benutzers.

21
Nicolò Martini

Es gibt ein aktuelles Format für Aktivitätsströme, das von einer Reihe bekannter Personen entwickelt wird.

http://activitystrea.ms/ .

Grundsätzlich hat jede Aktivität einen Akteur (der die Aktivität ausführt), ein Verb (die Aktion der Aktivität), ein Objekt (an dem der Akteur arbeitet) und ein Ziel.

Beispiel: Max hat einen Link auf die Pinnwand von Adam gepostet.

Die JSON-Spezifikation hat zum Zeitpunkt des Schreibens die Version 1.0 erreicht, in der das Muster für die Aktivität angegeben ist, die Sie anwenden können.

Ihr Format wurde bereits von BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, Superfeedr, TypePad, Windows Live, YIID und vielen anderen Anbietern übernommen.

14

Ich denke, dass eine Erklärung darüber, wie das Benachrichtigungssystem auf großen Websites funktioniert, in der Stapelüberlauf-Frage zu finden ist wie berechnen Websites für soziale Netzwerke die Aktualisierungen von Freunden? im Jeremy Wall ' s antwort. Er schlägt die Verwendung von Message Qeue vor und gibt zwei Open-Source-Software an, die diese implementieren:

  1. RabbitMQ
  2. Apache QPid

Siehe auch die Frage Wie kann ein sozialer Aktivitätsstrom am besten implementiert werden?

13
Nicolò Martini

Sie benötigen unbedingt eine performante und verteilte Nachrichtenwarteschlange. Aber es endet nicht damit, Sie müssen entscheiden, was als persistente Daten und was als transient und etc. gespeichert werden soll.

Wie auch immer, es ist wirklich eine schwierige Aufgabe, mein Freund, wenn Sie ein hochleistungsfähiges und skalierbares System suchen. Aber natürlich haben einige großzügige Ingenieure ihre Erfahrungen in diesem Bereich geteilt. LinkedIn hat kürzlich sein Nachrichtenwarteschlangensystem Kafka Open Source gemacht. Vorher hatte Facebook der Open Source Community bereits Scribe zur Verfügung gestellt. Kafka ist in Scala geschrieben und zunächst dauert es einige Zeit, bis es ausgeführt wird, aber ich habe es mit einigen virtuellen Servern getestet. Es ist sehr schnell.

http://blog.linkedin.com/2011/01/11/open-source-linkedin-kafka/

http://incubator.Apache.org/kafka/index.html

1
Cagatay Kalan

Anstatt Ihren eigenen zu erstellen, können Sie sich an einen Drittanbieter wenden, der über eine API verwendet wird. Ich habe eine mit dem Namen Collabinate ( http://www.collabinate.com ) gestartet, die ein Graph-Datenbank-Backend und einige ziemlich ausgefeilte Algorithmen für den Umgang mit großen Datenmengen auf eine sehr parallele und leistungsstarke Art und Weise enthält. Es verfügt zwar nicht über die Funktionen von Facebook oder Twitter, ist jedoch für die meisten Anwendungsfälle mehr als ausreichend, in denen Sie Aktivitätsströme, soziale Feeds oder Microblogging-Funktionen in eine Anwendung integrieren müssen.

0
Mafuba