Création d'un système de notification [fermé]

170

Je suis au début de la construction d'un système de notification de style Facebook pour notre page (type de jeu social) et je recherche maintenant quelle serait la meilleure façon de concevoir un tel système. Je ne suis pas intéressé par la façon de pousser les notifications à l'utilisateur ou quoi que ce soit du genre (pour l'instant même). Je recherche comment construire le système sur le serveur (comment stocker les notifications, où les stocker, comment les récupérer, etc.).

Donc ... certaines exigences que nous avons:

  • aux heures de pointe, nous avons environ 1k utilisateurs connectés simultanément (et beaucoup plus d'invités, mais ils n'ont pas d'importance ici car ils n'auront pas de notifications) qui généreront de nombreux événements
  • il y aura différents types de notifications (l'utilisateur A vous a ajouté comme ami, l'utilisateur B a commenté votre profil, l'utilisateur C a aimé votre image, l'utilisateur D vous a battu sur le jeu X, ...)
  • la plupart des événements généreront 1 notification pour 1 utilisateur (l'utilisateur X a aimé votre image), mais il y aura des cas où un événement générera de nombreuses notifications (c'est l'anniversaire de l'utilisateur Y par exemple)
  • les notifications devraient être regroupées; si, par exemple, quatre utilisateurs différents aiment une image, le propriétaire de cette image devrait recevoir une notification indiquant que quatre utilisateurs ont aimé l'image et non quatre notifications distinctes (tout comme FB)

OK, donc ce que je pensais, c'est que je devrais créer une sorte de file d'attente où je stockerais les événements lorsqu'ils se produisent. Ensuite, j'aurais un travail d'arrière-plan ( gearman ?) Qui examinerait cette file d'attente et générerait des notifications en fonction de ces événements. Ce travail stocke ensuite les notifications dans la base de données pour chaque utilisateur (donc si un événement affecte 10 utilisateurs, il y aura 10 notifications distinctes). Ensuite, lorsque l'utilisateur ouvrait une page avec la liste des notifications, je lisais toutes ces notifications pour lui (nous pensons à limiter cela à 100 dernières notifications) et les regroupais, puis les afficherais enfin.

Choses qui me préoccupent avec cette approche:

  • complexe comme l'enfer :)
  • est la base de données le meilleur stockage ici (nous utilisons MySQL) ou devrais-je utiliser autre chose (redis semble également être un bon choix)
  • que dois-je stocker comme notification? ID utilisateur, ID utilisateur qui a initié l'événement, type d'événement (afin que je puisse les regrouper et afficher le texte approprié) mais ensuite je ne sais pas comment stocker les données réelles de la notification (par exemple, URL et titre de l'image qui a été aimé). Dois-je simplement "cuire" cette information lorsque je génère la notification, ou dois-je stocker l'ID de l'enregistrement (image, profil, ...) affecté et extraire les informations de la base de données lors de l'affichage de la notification.
  • les performances devraient être correctes ici, même si je dois traiter 100 notifications à la volée lors de l'affichage de la page des notifications
  • problème de performance possible à chaque demande car je devrais afficher le nombre de notifications non lues à l'utilisateur (ce qui pourrait être un problème en soi puisque je regrouperais les notifications). Cela pourrait être évité si je générais la vue des notifications (où elles sont regroupées) en arrière-plan et non à la volée

Alors, que pensez-vous de ma solution proposée et de mes préoccupations? Veuillez commenter si vous pensez que je devrais mentionner autre chose qui serait pertinent ici.

Oh, nous utilisons PHP pour notre page, mais cela ne devrait pas être un facteur important ici, je pense.

Jan Hančič
la source
Combien de temps il vous a fallu pour construire ce système de notification en tant qu'efforts d'un seul homme. Je veux juste avoir une estimation pour établir les délais en conséquence.
Shaharyar
@Shaharyar Je pense que cela dépend de la complexité du système de notification.
tyan
J'ai utilisé le même système avec MySQL pour créer un système de notification basé sur les priorités. La bonne chose est qu'il s'adapte à quelques milliers d'utilisateurs, s'il va plus que cela, il explose, surtout avec Android et GCM. J'aimerais connaître des alternatives à MySQL comme redis, rabbitMQ, Kafka qui présentent naturellement une file d'attente de messages, sorte de fonctionnalité.
Ankit Marothi

Réponses:

168

Une notification concerne quelque chose (objet = événement, amitié ..) modifié (verbe = ajouté, demandé ..) par quelqu'un (acteur) et signalé à l'utilisateur (sujet). Voici une structure de données normalisée (bien que j'aie utilisé MongoDB). Vous devez informer certains utilisateurs des modifications. Il s'agit donc de notifications par utilisateur ... ce qui signifie que s'il y avait 100 utilisateurs impliqués, vous générez 100 notifications.

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

(Ajoutez des champs horaires là où vous le souhaitez)

Il s'agit essentiellement de regrouper les modifications par objet, de sorte que vous puissiez dire "Vous avez 3 demandes d'ami". Et le regroupement par acteur est utile, de sorte que vous puissiez dire "L'utilisateur James Bond a fait des changements dans votre lit". Cela permet également de traduire et de compter les notifications à votre guise.

Mais, étant donné que l'objet n'est qu'un ID, vous devez obtenir toutes les informations supplémentaires sur l'objet que vous souhaitez avec des appels séparés, à moins que l'objet ne change réellement et que vous souhaitiez afficher cet historique (par exemple, "l'utilisateur a changé le titre de l'événement en ... ")

Étant donné que les notifications sont proches du temps réel pour les utilisateurs du site, je les lierais au client nodejs + websockets avec php poussant la mise à jour vers nodejs pour tous les écouteurs à mesure que le changement est ajouté.

Artjom Kurapov
la source
1
notification_object.object identifie le type de changement, comme une chaîne "amitié" La référence réelle à l'objet modifié avec ses données supplémentaires dont je parle se trouve dans notification_change.notificationObjectID
Artjom Kurapov
2
Cela peut être une question stupide, mais avec cette configuration, que faites-vous une fois que l'utilisateur a vu ou agi sur la notification? Le supprimez-vous simplement de la base de données ou utilisez-vous simplement des dates pour voir si l'utilisateur s'est connecté depuis la création de la notification?
Jeffery Mills
4
Je sais que ce sujet est déjà assez ancien, mais je suis un peu perplexe au sujet du premier tableau, quel est exactement le but de ce tableau? quel est l'avantage d'avoir cela comme une table séparée par rapport à mettre l'ID utilisateur dans la table notification_object? En d'autres termes, quand allez-vous créer une nouvelle entrée dans la notification et quand allez-vous simplement ajouter un objet et passer à une notification existante avec cette structure?
Bas Goossen
3
@JefferyMills Vous pouvez avoir un champ de statut comme is_notification_readdans le notificationtableau et le marquer de manière appropriée si c'est le cas unread, readou deleted.
Kevin
2
J'ai également eu du mal à comprendre certains aspects de cette solution et j'ai posé une question distincte à ce sujet: dba.stackexchange.com/questions/99401/…
user45623
27

C'est vraiment une question abstraite, donc je suppose que nous allons simplement devoir en discuter au lieu de souligner ce que vous devriez ou ne devriez pas faire.

Voici ce que je pense de vos préoccupations:

  • Oui, un système de notification est complexe, mais pas comme l'enfer. Vous pouvez avoir de nombreuses approches différentes sur la modélisation et la mise en œuvre de tels systèmes, et ils peuvent avoir un niveau de complexité moyen à élevé;

  • Pesonally, j'essaye toujours de faire des choses basées sur des bases de données. Pourquoi? Parce que je peux garantir un contrôle total de tout ce qui se passe - mais ce n'est que moi, vous pouvez avoir le contrôle sans une approche basée sur une base de données; croyez-moi, vous voudrez contrôler cette affaire;

  • Permettez-moi de vous donner un exemple concret, afin que vous puissiez partir de quelque part. Au cours de la dernière année, j'ai modélisé et implémenté un système de notification dans une sorte de réseau social (pas comme Facebook, bien sûr). La façon dont j'y stockais les notifications? J'avais une notificationstable, où j'ai gardé le generator_user_id(l'ID de l'utilisateur qui génère la notification), le target_user_id(genre d'évident, n'est-ce pas?), Le notification_type_id(qui faisait référence à une table différente avec des types de notification), et tout les éléments nécessaires dont nous avons besoin pour remplir nos tables (horodatages, indicateurs, etc.). Ma notification_typestable avait une relation avec une notification_templatestable, qui stockait des modèles spécifiques pour chaque type de notification. Par exemple, j'avais un POST_REPLYtype, qui avait un type de modèle {USER} HAS REPLIED ONE OF YOUR #POSTS. De là, je viens de traiter le{}comme variable et #comme lien de référence;

  • Oui, les performances doivent et doivent être correctes. Lorsque vous pensez aux notifications, vous pensez au serveur qui se déplace de la tête aux pieds. Soit si vous allez le faire avec des requêtes ajax ou autre, vous allez devoir vous soucier des performances. Mais je pense que c'est une deuxième préoccupation;

Ce modèle que j'ai conçu n'est bien sûr pas le seul que vous puissiez suivre, ni le meilleur également. J'espère que ma réponse, au moins, vous suivra dans la bonne direction.

Daniel Ribeiro
la source
Pourquoi n'aurais-je pas le contrôle avec un autre magasin de données?
Jan Hančič
Eh bien, je n'ai pas dit ça. Ce que j'ai dit, c'est que je ne peux garantir le contrôle des données qu'avec une approche basée sur une base de données; mais ce n'est que moi. Je vais reformuler ça.
Daniel Ribeiro
@DanielRibeiro les espaces réservés ({...}) dans le modèle de notification doivent remplacer les données des espaces réservés des différents ensembles de tables de la base de données pour les différents types de notifications. Par exemple, un modèle est "{utilisateur} a aimé votre photo", un autre modèle est "Votre {nom de page} a un nouveau style". Etc. {PageName} et {user} et d'autres espaces réservés seront mappés à partir de la table de base de données différente, donc quel devrait être le schéma pour obtenir dynamiquement la valeur des espaces réservés.
Ashish Shukla
DanielRibeiro comment vous avez remplacé les espaces réservés comme demandé par @Ashish Shukla,
Shantaram Tupe
@AshishShukla avez-vous utilisé ou remplacé des espaces réservés, et comment?
Shantaram Tupe
8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Cela semble une bonne réponse plutôt que d'avoir 2 collections. Vous pouvez interroger par nom d'utilisateur, objet et isRead pour obtenir de nouveaux événements (comme 3 demandes d'amis en attente, 4 questions posées, etc.)

Faites-moi savoir s'il y a un problème avec ce schéma.

Kaphy
la source
3
La première réponse a utilisé une structure de données normalisée, ce qui signifie aucune redondance dans les tables. Votre réponse fait-elle cela?
Aaron Hall
4

Personnellement, je ne comprends pas très bien le diagramme de la réponse acceptée, donc je vais joindre un diagramme de base de données basé sur ce que je pourrais apprendre de la réponse acceptée et d'autres pages.

entrez la description de l'image ici

Les améliorations sont bien reçues.

Jason Glez
la source
On dirait que message_template serait dans la table NotificationType. Il semble également que l'url main_url se trouve dans la table des notifications, vous pouvez alors éliminer la table Notification_Message. Pouvez-vous expliquer la raison pour laquelle vous disposez de la table NotificationMessage seule?
Jeff Ryan