Sistema di notifiche con troppi abbonati

1

Nella mia applicazione gli utenti possono iscriversi ad altri utenti, come in ogni social network. Tuttavia sto riscontrando qualche problema quando un utente ha troppi abbonati. Ogni volta che un utente pubblica qualcosa, tutti i suoi abbonati vengono avvisati tramite il sistema di notifica. Quando un utente ha come 2000 abbonati o anche più, questo significa che devo inserire 2000 righe nella tabella notifications , che può richiedere un secondo o due. Avendo molti utenti che postano cose ho la sensazione che questo tavolo si riempia molto velocemente e non riesco a pensare ad un'altra realizzazione.

Lo schema corrente è

CREATE TABLE IF NOT EXISTS 'notifications' (
  'id' int(10) unsigned NOT NULL AUTO_INCREMENT,
  'user_id' int(10) unsigned NOT NULL,
  'text' text NOT NULL,
  'data' text NOT NULL,
  'time' datetime NOT NULL,
  'seen' enum('0','1') NOT NULL DEFAULT '0',
  PRIMARY KEY ('id','user_id')
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Come posso superare questo problema?

    
posta php_nub_qq 28.09.2014 - 22:26
fonte

4 risposte

3

Il tuo caso d'uso è questo (per favore correggimi se è sbagliato):

Users post updates. Users can have subscribers. Subscribers see the updates, and can filter based on which ones they have not seen before.

Il tuo modello di dati non dovrebbe quindi contenere una tabella di notifiche che elenca le notifiche per destinatario.

Il modello di dati sarebbe simile a questo:

  • Utenti (user_id, nome): l'elenco di utenti
  • Sottoscrizioni (from_user_id, to_user_id): la relazione tra abbonato / autore
  • Post (post_id, user_id, text): i post scritti, un record per post (collegato all'utente che ha scritto il messaggio)
  • Visite (post_id, user_id, date): la data in cui il post è stato visitato per la prima volta da un utente specifico

L'insieme di post che un utente non ha ancora visto è quindi il set di post degli autori a cui sono iscritti, sottratti con il set di post trovato nella tabella delle visite.

Entrambi gli invio e lettura di una notifica sono quindi un aggiornamento a riga singola.

    
risposta data 29.09.2014 - 14:09
fonte
5

Non inserire le 2000 righe quando l'utente pubblica qualcosa.

Invece, invia un messaggio attraverso un messaggio che dice "Nuovo post, ID è x". Quindi fare in modo che il processo in background tolga il messaggio dalla coda e lo elabori, inclusa la generazione di notifiche.

Fondamentalmente, si restituisce una pagina web all'utente appena possibile facendo solo l'essenziale e poi si fa tutto il lavoro pesante su un'attività in background che l'utente non vede, e quindi può impiegare tutto il tempo che vuole (con in ragione).

    
risposta data 29.09.2014 - 11:07
fonte
3

Per un sistema che può gestire utenti di > 2000, l'aggiunta di 2000 record a una tabella non dovrebbe essere un grosso problema, altrimenti hai scelto l'hardware sbagliato. Se uno o due secondi bloccano il processo principale troppo a lungo, aggiungi i record in modo asincrono in un thread o processo separato.

E se hai dubbi sull'ottenere troppi record di notifica in quella tabella, pensa a quanto tempo queste notifiche devono davvero essere archiviate. Saranno davvero necessari per essere archiviati una volta che la notifica è stata vista? Devono essere conservati per più di, ad esempio, 60 giorni? Questi pensieri dovrebbero aiutarti a trovare una strategia di pulizia appropriata.

    
risposta data 28.09.2014 - 22:58
fonte
0

Puoi aumentare notevolmente la velocità inserendo i tuoi inserti in una transazione. Puoi anche spostare le tue istruzioni di preparazione e rilegatura all'esterno, se necessario.

L'idea che uso generalmente quando lavoro con le transazioni è simile a questo (semi-pseudo-codice):

try {
    // First of all, let's begin a transaction
    $db->beginTransaction();

    // A set of queries; if one fails, an exception should be thrown
    $db->query('first query');
    $db->query('second query');
    $db->query('third query');

    // If we arrive here, it means that no exception was thrown
    // i.e. no query has failed, and we can commit the transaction
    $db->commit();
} catch (Exception $e) {
    // An exception has been thrown
    // We must rollback the transaction
    $db->rollback();
}

Esempio tratto da questo link: - link

    
risposta data 29.09.2014 - 08:31
fonte

Leggi altre domande sui tag