web-dev-qa-db-fra.com

Comment implémenter le flux d'activité dans un réseau social

Je développe mon propre réseau social, et je n'ai pas trouvé sur le Web d'exemples de mise en œuvre du flux d'actions des utilisateurs ... Par exemple, comment filtrer les actions pour chaque utilisateur? Comment stocker les événements d'action? Quel modèle de données et quel modèle d'objet puis-je utiliser pour le flux d'actions et pour les actions elles-mêmes?

132
Nicolò Martini

Résumé : Pour environ 1 million d'utilisateurs actifs et 150 millions d'activités stockées, je fais simple:

  • Utilisez une base de données relationnelle pour stocker des activités uniques (1 enregistrement par activité/"événement"). Rendez les enregistrements aussi compacts que possible. Structure permettant de saisir rapidement un lot d'activités par ID d'activité ou en utilisant un ensemble d'identifiants d'amis avec des contraintes de temps.
  • Publiez les ID d'activité dans Redis chaque fois qu'un enregistrement d'activité est créé, en l'ajoutant à la liste "Flux d'activité" de chaque utilisateur ami/abonné qui devrait voir l'activité.

Requête Redis pour obtenir le flux d'activité pour n'importe quel utilisateur, puis récupérez les données connexes de la base de données selon vos besoins. Revenez à la recherche de la base de données par heure si l'utilisateur a besoin de naviguer très loin dans le temps (si vous le proposez)


J'utilise une vieille table MySQL pour gérer environ 15 millions d'activités.

Cela ressemble à quelque chose comme ça:

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 M'indique le type d'activité, source_id M'indique le compte rendu de l'activité. Donc, si le type d'activité signifie "favori ajouté", je sais que l'identificateur source_id fait référence à l'ID d'un enregistrement favori.

Les parent_id/parent_type Sont utiles pour mon application - ils me disent en quoi l'activité est liée. Si un livre a été favorisé, alors parent_id/parent_type me dirait que l'activité concerne un livre (type) avec une clé primaire donnée (id)

J'indexe sur (user_id, time) Et recherche les activités qui sont user_id IN (...friends...) AND time > some-cutoff-point. Découper l'identifiant et choisir un autre index clusterisé peut être une bonne idée - je n'ai pas expérimenté cela.

Jolies choses de base, mais cela fonctionne, c'est simple et il est facile de travailler avec vos besoins changent. De plus, si vous n'utilisez pas MySQL, vous pourrez peut-être faire mieux en termes d'index.


Pour un accès plus rapide aux activités les plus récentes, j’ai expérimenté Redis . Redis stocke toutes ses données en mémoire, vous ne pouvez donc pas y mettre toutes vos activités, mais vous pouvez en stocker suffisamment pour la plupart des écrans fréquemment consultés sur votre site. Les 100 plus récents pour chaque utilisateur ou quelque chose comme ça. Avec Redis dans le mix, cela pourrait fonctionner comme ceci:

  • Créez votre enregistrement d'activité MySQL
  • Pour chaque ami de l'utilisateur qui a créé l'activité, insérez l'ID dans la liste de ses activités dans Redis.
  • Couper chaque liste aux X derniers éléments

Redis est rapide et offre un moyen de canaliser les commandes sur une seule connexion. Par conséquent, transmettre une activité à 1 000 amis prend des millisecondes.

Pour une explication plus détaillée de ce dont je parle, voir l'exemple de Redis sur Twitter: http://redis.io/topics/Twitter-clone

Mise à jour en février 2011 J'ai 50 millions d'activités actives pour le moment et je n'ai rien changé. Une bonne chose à propos de faire quelque chose de semblable à ceci est qu’il utilise des lignes compactes et petites. Je prévois d’apporter des changements qui impliqueraient beaucoup plus d’activités et davantage de requêtes sur ces activités, et j’utiliserai certainement Redis pour accélérer les choses. J'utilise Redis dans d'autres domaines et cela fonctionne vraiment bien pour certains types de problèmes.

Mise à jour en juillet 2014 Nous avons environ 700 000 utilisateurs actifs par mois. Depuis quelques années, j'utilise Redis (comme décrit dans la liste à puces) pour stocker les 1 000 derniers identifiants d'activité de chaque utilisateur. Il y a généralement environ 100 millions d'enregistrements d'activité dans le système. Ils sont toujours stockés dans MySQL et ont toujours la même présentation. Ces enregistrements nous permettent de nous en sortir avec moins de mémoire Redis, ils servent d’enregistrement de données d’activité et nous les utilisons si les utilisateurs ont besoin de rechercher une page plus loin dans le temps.

Ce n'était pas une solution intelligente ou particulièrement intéressante, mais elle m'a bien servi.

233
casey

Ceci est ma mise en œuvre d'un flux d'activité, en utilisant mysql. Il existe trois classes: Activity, ActivityFeed, Subscriber.

L'activité représente une entrée d'activité et son tableau ressemble à ceci:

id
subject_id
object_id
type
verb
data
time

Subject_id est l'identifiant de l'objet effectuant l'action, object_id l'identifiant de l'objet qui reçoit l'action. type et verb décrivent l’action elle-même (par exemple, si un utilisateur ajoute un commentaire à un article, il doit être respectivement "commentaire" et "créé"), les données contiennent des données supplémentaires afin de: éviter les jointures (par exemple, il peut contenir le nom du sujet et le nom de famille, le titre et l'url de l'article, le corps du commentaire, etc.).

Chaque activité appartient à un ou plusieurs ActivityFeeds, et ils sont reliés par une table qui ressemble à ceci:

feed_name
activity_id

Dans mon application, j'ai un flux pour chaque utilisateur et un pour chaque élément (généralement des articles de blog), mais ils peuvent correspondre à vos préférences.

Un abonné est généralement un utilisateur de votre site, mais il peut également s'agir de n'importe quel objet de votre modèle d'objet (par exemple, un article peut être abonné à feed_action de son créateur).

Chaque abonné appartient à un ou plusieurs ActivityFeeds et, comme ci-dessus, ils sont reliés par un tableau de liens de ce type:

feed_name
subscriber_id
reason

Le champ reason explique ici pourquoi l'abonné a souscrit le flux. Par exemple, si un utilisateur a ajouté un signet à un article de blog, la raison en est "signet". Cela m'aide plus tard à filtrer les actions pour les notifications aux utilisateurs.

Pour récupérer l'activité pour un abonné, je fais une simple jointure des trois tables. La jointure est rapide car je sélectionne peu d’activités grâce à une condition WHERE qui ressemble à maintenant - time > some hours. J'évite les autres jointures grâce au champ de données de la table d'activités.

Plus d'explications sur le champ reason. Si, par exemple, je souhaite filtrer les actions pour les notifications par courrier électronique adressées à l'utilisateur et que celui-ci a ajouté un blog à un signet (et qu'il s'abonne au fil de publication avec le motif "favori"), je ne souhaite pas que l'utilisateur reçoive notifications par courrier électronique à propos des actions sur cet élément, alors que s'il commente la publication (et qu'il s'abonne au flux de publication avec la raison 'commentaire'), je souhaite qu'il soit averti lorsque d'autres utilisateurs ajoutent des commentaires à la même publication. Le champ Motif m'aide dans cette discrimination (je l'ai implémentée via une classe ActivityFilter), ainsi que dans les préférences de notification de l'utilisateur.

21
Nicolò Martini

Il existe actuellement un format de flux d'activité développé par un groupe de personnes bien connues.

http://activitystrea.ms/ .

Fondamentalement, chaque activité a un acteur (qui l'exécute), un verbe (l'action de l'activité), un objet (sur lequel l'acteur s'exécute) et une cible.

Par exemple: Max a posté un lien vers le mur d'Adam.

Leur spécification JSON a atteint la version 1.0 au moment de la rédaction, qui indique le modèle d'activité que vous pouvez appliquer.

Leur format a déjà été adopté par la BBC, Gnip, Google Buzz Gowalla, IBM, MySpace, Opera, Socialcast, SuperFeedr, TypePad, Windows Live, YIID et bien d’autres.

14
Sơn Trần-Nguyễn

Je pense qu’une explication sur le fonctionnement du système de notifications sur les grands sites Web se trouve dans la question du débordement de la pile comment les sites de réseautage social calculent-ils les mises à jour des amis? , dans le Jeremy Wall ' s réponse. Il suggère l'utilisation de Message Qeue et indique deux logiciels Open Source qui l'implémentent:

  1. RabbitMQ
  2. Apache QPid

Voir aussi la question Quelle est la meilleure façon de mettre en œuvre un flux d’activités sociales?

13
Nicolò Martini

Vous avez absolument besoin d'une file d'attente de messages distribuée et performante. Mais cela ne s'arrête pas là, vous devrez décider de ce qu'il faut stocker en tant que données persistantes et de ce qui est transitoire, etc.

Quoi qu’il en soit, c’est vraiment une tâche difficile, mon ami, si vous recherchez un système hautes performances et évolutif. Mais, bien sûr, certains ingénieurs généreux ont partagé leur expérience à ce sujet. LinkedIn a récemment créé son système de file d'attente de messages Kafka open source. Avant cela, Facebook avait déjà fourni Scribe à la communauté open source. Kafka est écrit en Scala et au début cela prend un certain temps pour le faire fonctionner mais j’ai testé avec quelques serveurs virtuels. C’est vraiment rapide.

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

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

1
Cagatay Kalan

Au lieu de lancer le vôtre, vous pouvez vous tourner vers un service tiers utilisé via une API. J'ai démarré un système appelé Collabinate ( http://www.collabinate.com ) qui possède une base de données de graphes et des algorithmes assez sophistiqués permettant de traiter de grandes quantités de données de manière hautement concurrentielle et performante. Bien que Facebook ou Twitter ne soit pas doté de toutes les fonctionnalités, il est largement suffisant pour la plupart des cas d'utilisation où vous devez créer des flux d'activité, des flux sociaux ou des fonctionnalités de micro-blogging dans une application.

0
Mafuba