Costruire un sistema di notifica [chiuso]


170

Sono all'inizio della costruzione di un sistema di notifica in stile Facebook per la nostra pagina (tipo di social gaming) e ora sto cercando quale sarebbe il modo migliore per progettare tale sistema. Non sono interessato a come inviare notifiche all'utente o cose del genere (per ora anche). Sto cercando come costruire il sistema sul server (come archiviare le notifiche, dove memorizzarle, come recuperarle, ecc ...).

Quindi ... alcuni requisiti che abbiamo:

  • nelle ore di punta abbiamo circa 1k utenti con accesso simultaneo (e molti più ospiti, ma non contano qui perché non avranno notifiche) che genereranno molti eventi
  • ci saranno diversi tipi di notifiche (l'utente A ti ha aggiunto come amico, l'utente B ha commentato il tuo profilo, all'utente C è piaciuta la tua immagine, l'utente D ti ha battuto sul gioco X, ...)
  • la maggior parte degli eventi genererà 1 notifica per 1 utente (all'utente X è piaciuta la tua immagine), ma ci saranno casi in cui un evento genererà molte notifiche (ad esempio il compleanno dell'utente Y)
  • le notifiche dovrebbero essere raggruppate insieme; se ad esempio a quattro utenti diversi piace un'immagine, il proprietario di quell'immagine dovrebbe ricevere una notifica che indica che l'immagine è piaciuta a quattro utenti e non a quattro notifiche separate (proprio come FB)

OK, quindi quello che stavo pensando è che dovevo creare una sorta di coda in cui avrei memorizzato gli eventi quando si verificano. Quindi avrei un lavoro in background ( gearman ?) Che guarderebbe quella coda e genererebbe notifiche basate su quegli eventi. Questo lavoro memorizza quindi le notifiche nel database per ciascun utente (quindi se un evento interessa 10 utenti, ci sarebbero 10 notifiche separate). Quindi, quando l'utente apriva una pagina con l'elenco delle notifiche, leggevo tutte quelle notifiche per lui (pensiamo di limitare questa a 100 ultime notifiche) e le raggruppa e poi le mostra.

Le cose di cui mi preoccupo con questo approccio:

  • complesso da morire :)
  • il database è lo spazio di archiviazione migliore qui (stiamo usando MySQL) o dovrei usare qualcos'altro (anche redis sembra una buona scelta)
  • cosa devo memorizzare come notifica? ID utente, ID utente che ha avviato l'evento, tipo di evento (in modo da poterli raggruppare e visualizzare il testo appropriato) ma poi non so come archiviare i dati effettivi della notifica (ad esempio URL e titolo dell'immagine che è piaciuto). Devo solo "infornare" tali informazioni quando generi la notifica, oppure devo memorizzare l'ID del record (immagine, profilo, ...) interessato ed estrarre le informazioni dal DB quando visualizzo la notifica.
  • le prestazioni dovrebbero essere OK qui, anche se devo elaborare 100 notifiche al volo quando visualizzo la pagina delle notifiche
  • possibile problema di prestazioni su ogni richiesta perché dovrei visualizzare il numero di notifiche non lette all'utente (che potrebbe essere un problema a sé stante poiché raggrupperei le notifiche). Ciò potrebbe essere evitato, tuttavia, se ho generato la vista delle notifiche (in cui sono raggruppate) in background e non al volo

Cosa ne pensi della mia soluzione proposta e delle mie preoccupazioni? Per favore, commenta se pensi che dovrei menzionare qualcos'altro che sarebbe rilevante qui.

Oh, stiamo usando PHP per la nostra pagina, ma questo non dovrebbe essere un grande fattore qui penso.


Quanto tempo ci è voluto per costruire questo sistema di notifica come un solo uomo. Voglio solo avere una stima per fare le scadenze di conseguenza.
Shaharyar,

@Shaharyar Penso che dipenda dalla complessità del sistema di notifica.
tyan,

Ho usato lo stesso sistema con MySQL per creare un sistema di notifica basato sulla priorità. La cosa buona è che si adatta a poche migliaia di utenti, se va oltre, esplode, specialmente con Android e GCM. Mi piacerebbe conoscere alternative a MySQL come redis, rabbitMQ, Kafka che mostrano naturalmente una coda di messaggi, un tipo di funzionalità.
Ankit Marothi,

Risposte:


168

Una notifica riguarda qualcosa (oggetto = evento, amicizia ..) che viene modificato (verbo = aggiunto, richiesto ...) da qualcuno (attore) e segnalato all'utente (soggetto). Ecco una struttura di dati normalizzata (anche se ho usato MongoDB). È necessario informare alcuni utenti delle modifiche. Quindi sono le notifiche per utente ... il che significa che se c'erano 100 utenti coinvolti, si generano 100 notifiche.

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

(Aggiungi campi temporali dove ritieni opportuno)

Questo è fondamentalmente per raggruppare le modifiche per oggetto, in modo da poter dire "Hai 3 richieste di amicizia". E raggruppare per attore è utile, in modo da poter dire "L'utente James Bond ha apportato modifiche nel tuo letto". Ciò consente anche di tradurre e contare le notifiche come preferisci.

Ma poiché l'oggetto è solo un ID, dovresti ottenere tutte le informazioni extra sull'oggetto che desideri con chiamate separate, a meno che l'oggetto non cambi effettivamente e tu voglia mostrare quella cronologia (quindi ad esempio "l'utente ha cambiato il titolo dell'evento in ... ")

Poiché le notifiche sono quasi in tempo reale per gli utenti del sito, le collegherei a nodejs + websocket client con php che invia l'aggiornamento a nodejs per tutti i listener man mano che vengono aggiunte le modifiche.


1
notification_object.object identifica il tipo di modifica, come una stringa "amicizia" Il riferimento effettivo all'oggetto modificato con i suoi dati extra di cui parlo è in notification_change.notificationObjectID
Artjom Kurapov

2
Potrebbe trattarsi di una domanda stupida, ma con questa impostazione cosa fai una volta che l'utente ha visto o agito sulla notifica? Lo rimuovi dal database o usi solo le date per vedere se l'utente ha effettuato l'accesso da quando è stata creata la notifica?
Jeffery Mills,

4
So che questo argomento è già piuttosto vecchio, tuttavia sono un po 'perplesso sul primo tavolo, qual è esattamente lo scopo di questo tavolo? qual è il vantaggio di avere questo come una tabella separata rispetto a mettere userID nella tabella notification_object? In altre parole, quando creerai una nuova voce nella notifica e quando aggiungerai semplicemente un oggetto e passerai a una notifica esistente con questa struttura?
Bas Goossen,

3
@JefferyMills Potresti avere un campo di stato come is_notification_readnella notificationtabella e contrassegnarlo in modo appropriato se lo è unread, reado deleted.
Kevin,

2
Ho anche faticato a comprendere alcuni aspetti di questa soluzione e ho formulato una domanda separata al riguardo: dba.stackexchange.com/questions/99401/…
user45623

27

Questa è davvero una domanda astratta, quindi immagino che dovremo solo discuterne invece di sottolineare cosa dovresti o non dovresti fare.

Ecco cosa penso delle tue preoccupazioni:

  • Sì, un sistema di notifica è complesso, ma non così infernale. Puoi avere molti approcci diversi sulla modellazione e l'implementazione di tali sistemi e possono avere da un livello medio ad un livello di complessità elevato;

  • A livello economico, cerco sempre di creare cose basate su database. Perché? Perché posso garantire il pieno controllo di tutto ciò che sta succedendo, ma sono solo io, puoi avere il controllo senza un approccio basato su database; fidati di me, vorrai avere il controllo su quel caso;

  • Permettimi di esemplificare un caso reale per te, così puoi iniziare da qualche parte. L'anno scorso ho modellato e implementato un sistema di notifica in una specie di social network (ovviamente non come Facebook). Come ho usato per archiviare le notifiche lì? Avevo una notificationstabella, in cui conservavo generator_user_id(l'ID dell'utente che sta generando la notifica), il target_user_id(tipo di ovvio, non è vero?), Il notification_type_id(che faceva riferimento a una tabella diversa con tipi di notifica) e tutto quella roba necessaria di cui abbiamo bisogno per riempire le nostre tabelle (timestamp, bandiere, ecc.). La mia notification_typestabella aveva una relazione con una notification_templatestabella, che memorizzava modelli specifici per ogni tipo di notifica. Ad esempio, avevo un POST_REPLYtipo, che aveva un modello simile {USER} HAS REPLIED ONE OF YOUR #POSTS. Da lì, ho appena trattato il{}come variabile e #come link di riferimento;

  • Sì, le prestazioni dovrebbero e devono essere ok. Quando pensi alle notifiche, pensi al server che spinge dalla testa ai piedi. O se lo farai con richieste ajax o altro, dovrai preoccuparti delle prestazioni. Ma penso che sia una seconda preoccupazione;

Quel modello che ho progettato non è, ovviamente, l'unico che puoi seguire, né il migliore. Spero almeno che la mia risposta ti segua nella giusta direzione.


Perché non dovrei avere il controllo con qualche altro archivio dati?
Jan Hančič,

Beh, non l'ho detto. Quello che ho detto è che posso garantire il controllo dei dati solo con un approccio basato su database; ma sono solo io. Lo riformulerò.
Daniel Ribeiro,

@DanielRibeiro i segnaposto ({...}) nel modello di notifica devono sostituire i dati dei segnaposto dalle diverse serie di tabelle nel database per il diverso tipo di notifiche. Ad esempio, un modello è "A {user} è piaciuta la tua foto.", Un altro modello è "Il tuo {Nome pagina} ha un nuovo like". Ecc. {PageName} e {user} e altri segnaposto verranno mappati dalla diversa tabella del database, quindi quale dovrebbe essere lo schema per ottenere dinamicamente il valore dei segnaposto.
Ashish Shukla,

DanielRibeiro come hai sostituito i segnaposto come richiesto da @Ashish Shukla,
Shantaram Tupe

@AshishShukla hai usato o sostituito i segnaposto e come?
Shantaram Tupe,

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

Questa sembra una buona risposta piuttosto che avere 2 raccolte. Puoi eseguire query per nome utente, oggetto e isRead per ottenere nuovi eventi (come 3 richieste di amicizia in sospeso, 4 domande poste ecc ...)

Fammi sapere se c'è un problema con questo schema.


3
La risposta principale utilizzava una struttura di dati normalizzata, il che significa che non vi sono ridondanze nelle tabelle. La tua risposta lo fa?
Aaron Hall

4

Personalmente non capisco molto bene il diagramma della risposta accettata, quindi allego un diagramma del database basato su ciò che potrei imparare dalla risposta accettata e da altre pagine.

inserisci qui la descrizione dell'immagine

I miglioramenti sono ben accolti.


Sembra che message_template sarebbe nella tabella NotificationType. Sembra anche che main_url si trovi nella tabella delle notifiche, quindi è possibile eliminare la tabella Notification_Message. Puoi spiegare il motivo per cui hai la tabella NotificationMessage da sola?
Jeff Ryan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.