170 votes

Mise en place d'un système de notification

Je suis au début de la construction d'un système de notification de style Facebook pour notre page (type 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 quelque chose comme ça (même pour l'instant). Je recherche comment construire le système sur le serveur (comment stocker les notifications, où les stocker, comment les récupérer etc...).

Donc ... quelques exigences que nous avons :

  • aux heures de pointe, nous avons environ 1 000 utilisateurs connectés simultanément (et beaucoup plus d'invités, mais ils n'ont pas d'importance ici car ils n'ont pas de notifications), ce qui génère 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 au jeu X, ...)
  • la plupart des événements génèrent une notification pour un utilisateur (l'utilisateur X a aimé votre image), mais il y a des cas où un événement génère plusieurs 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 (comme le fait FB)

Je me disais donc que je devrais créer une sorte de file d'attente où je pourrais stocker les événements lorsqu'ils se produisent. Ensuite, j'aurais un travail en arrière-plan ( réducteur ?) qui examinerait cette file d'attente et générerait des notifications en fonction de ces événements. Cette tâche stockerait ensuite les notifications dans la base de données pour chaque utilisateur (ainsi, si un événement affecte 10 utilisateurs, il y aurait 10 notifications distinctes). Ensuite, lorsque l'utilisateur ouvrirait une page contenant la liste des notifications, je lirais toutes ces notifications pour lui (nous pensons limiter cela à 100 notifications récentes), je les regrouperais et je les afficherais enfin.

Ce qui me préoccupe dans cette approche :

  • complexe comme l'enfer :)
  • La base de données est-elle la meilleure solution de stockage ici (nous utilisons MySQL) ou dois-je utiliser autre chose (redis semble être une bonne solution également) ?
  • Qu'est-ce que je dois stocker dans une notification ? l'ID de l'utilisateur, l'ID de l'utilisateur qui a initié l'événement, le type d'événement (pour que je puisse les grouper et afficher le texte approprié) mais ensuite je ne sais pas comment stocker les données réelles de la notification (par exemple l'URL et le titre de l'image qui a été aimée). Dois-je simplement intégrer cette information lorsque je génère la notification, ou dois-je stocker l'ID de l'enregistrement (image, profil, ...) affecté et extraire l'information 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 de notifications.
  • problème de performance possible à chaque requête 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). Ce problème 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 la solution que je propose et de mes préoccupations ? N'hésitez pas à commenter si vous pensez que je dois 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.

0 votes

Combien de temps il vous a fallu pour construire ce système de notification en tant qu'effort individuel. Je veux juste avoir une estimation pour faire les délais en conséquence.

0 votes

@Shaharyar Je pense que cela dépend de la complexité du système de notification.

0 votes

J'ai utilisé le même système avec MySQL pour construire un système de notification basé sur les priorités. La bonne chose est qu'il s'adapte à quelques milliers d'utilisateurs, si cela va plus loin, il explose, surtout avec Android et GCM. J'aimerais connaître des alternatives à MySQL comme redis, rabbitMQ, Kafka qui présentent naturellement une queue de message, une sorte de fonctionnalité.

167voto

Artjom Kurapov Points 2808

Une notification concerne quelque chose (objet = événement, amitié..) qui est 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 notifier certains utilisateurs des changements. Il s'agit donc de notifications par utilisateur ce qui signifie que s'il y a 100 utilisateurs concerné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 de temps là où vous le souhaitez)

Il s'agit essentiellement de regrouper les modifications par objet, afin de pouvoir dire "Vous avez 3 demandes d'amis". Il est également utile de regrouper les modifications par acteur, afin de pouvoir dire "L'utilisateur James Bond a modifié votre lit". Cela permet également de traduire et de compter les notifications comme vous le souhaitez.

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

Puisque les notifications sont proches du temps réel pour les utilisateurs du site, je les lierais avec nodejs + websockets client avec php poussant la mise à jour à nodejs pour tous les auditeurs au fur et à mesure que le changement est ajouté.

0 votes

+1 @Artjom, c'est un poste génial. Je me demandais, vous mentionnez object est juste un identifiant. Comment savoir de quel type d'objet il s'agit ? Par exemple, il peut s'agir d'une demande d'ami, ou de n'importe quoi d'autre, alors comment lier la notification à l'événement approprié ? Merci beaucoup.

1 votes

Notification_object.object identifie le type de changement, comme une chaîne de caractères "amitié" La référence réelle à l'objet modifié avec ses données supplémentaires dont je parle est dans notification_change.notificationObjectID

0 votes

Je vois, c'est très intelligent. Dans ce cas, avez-vous besoin de stocker la classe de l'objet dans la base de données ? Ou bien avez-vous un moyen de récupérer la classe à partir de la chaîne stockée dans la base de données ? notification_object.object (comme 'friendship') ? parce que, si nous voulons obtenir des informations sur l'objet de notification, nous devons le charger en utilisant sa classe et ses identifiants. Est-ce que j'ai raison ? Avez-vous une astuce pour cela ? comme un écouteur d'événements, ou quelque chose qui convertit les données de l'objet de notification en données d'identification ? notification_object.object et son identifiant dans l'objet réel ? Merci beaucoup @Artjom, c'est une aide précieuse :)

27voto

Daniel Ribeiro Points 3546

Il s'agit d'une question vraiment abstraite. Je suppose donc que nous allons devoir en discuter au lieu de vous indiquer 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 autant que l'enfer. Il existe de nombreuses approches différentes de la modélisation et de la mise en œuvre de tels systèmes, qui peuvent présenter un niveau de complexité moyen à élevé ;

  • Pesonalement, j'essaie toujours de faire en sorte que les choses soient 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 la base de données ; croyez-moi, vous allez vouloir avoir le contrôle sur cette affaire ;

  • Laissez-moi vous donner un exemple concret, pour que vous puissiez partir de quelque part. L'année dernière, j'ai modélisé et mis en œuvre 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 un notifications table, où je gardais les generator_user_id (l'identifiant de l'utilisateur qui génère la notification), l'élément target_user_id (plutôt évident, n'est-ce pas ?), la notification_type_id (qui fait référence à une table différente avec les types de notification), et tous les éléments nécessaires pour remplir nos tables (timestamps, drapeaux, etc). Mon notification_types utilisé pour avoir une relation avec une notification_templates qui stocke des modèles spécifiques pour chaque type de notification. Par exemple, j'avais un POST_REPLY qui avait un modèle un peu comme {USER} HAS REPLIED ONE OF YOUR #POSTS . A partir de là, j'ai juste traité le {} comme une variable et le # comme lien de référence ;

  • Oui, la performance debe y doit être ok. Quand on pense aux notifications, on pense à un serveur qui pousse de la tête aux pieds. Et si vous le faites avec des requêtes ajax ou autre, vous allez devoir vous soucier des performances. Mais je pense que c'est une préoccupation secondaire ;

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

0 votes

Pourquoi n'aurais-je pas le contrôle avec un autre magasin de données ?

0 votes

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 axée sur la base de données ; mais ce n'est que moi. Je vais reformuler ça.

0 votes

@DanielRibeiro les caractères de remplacement ({...}) dans le modèle de notification doivent remplacer les données des caractères de remplacement des différents ensembles de tables dans 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 {Pagename} a un nouveau like." Etc. {PageName} et {user} et d'autres caractères de remplissage seront mappés à partir des différentes tables de la base de données, donc quel devrait être le schéma pour obtenir la valeur des caractères de remplissage dynamiquement.

8voto

user3013980 Points 6
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Cela semble être une bonne réponse plutôt que d'avoir deux 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.

3 votes

La meilleure réponse utilisait une structure de données normalisée, c'est-à-dire sans redondance dans les tableaux. Votre réponse fait-elle cela ?

4voto

Jason Glez Points 405

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

enter image description here

Les améliorations sont bien accueillies.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X