Utilizzo di Memcached: è buona prassi aggiornare la cache durante l'aggiornamento del database?

13

Questa domanda riguarda le migliori pratiche in architettura.

La nostra architettura attuale

Ho una classe PHP che accede a MySQL per le informazioni dell'utente. Chiamiamolo User . User è accessibile molte volte, quindi abbiamo implementato livelli di memorizzazione nella cache per ridurre il carico.

Il primo livello è ciò che chiamiamo la cache "per richiesta". Dopo che i dati sono stati recuperati da MySQL, archiviamo i dati in una proprietà privata di User . Qualsiasi richiesta successiva per i dati restituisce la proprietà invece di richiedere nuovamente i dati da MySQL.

Poiché la richiesta Web è valida e muore in base alle richieste, questa cache impedisce all'applicazione di accedere a MySQL più di una volta in una singola richiesta.

Il nostro secondo livello è Memcached. Quando la proprietà privata è vuota, per prima cosa controlliamo Memcached per i dati. Se Memcached è vuoto, interrogiamo MySQL per i dati, aggiorna Memcached e aggiorniamo la proprietà privata di User .

La domanda

La nostra applicazione è un gioco, ea volte è imperativo che alcuni dati siano il più aggiornati possibile. Nell'intervallo di circa cinque minuti, una richiesta di lettura dei dati dell'utente potrebbe verificarsi 10 o 11 volte; quindi potrebbe verificarsi un aggiornamento. Le richieste di lettura successive devono essere aggiornate o i meccanismi di gioco non riescono.

Quindi, quello che abbiamo fatto è implementare un pezzo di codice che viene eseguito quando si verifica un aggiornamento del database. Questo codice imposta la chiave in Memcached con i dati aggiornati, quindi tutte le richieste successive a Memcached sono aggiornate.

È ottimale? Ci sono problemi di prestazioni o altri "trucchi" di cui dovremmo essere a conoscenza quando proviamo a mantenere una sorta di "cache vivente" come questa?

    
posta Stephen 29.12.2011 - 17:37
fonte

2 risposte

10

La mia raccomandazione è di guardare il profilo di utilizzo e i requisiti per la cache.

Non vedo alcun motivo per cui lascerai i dati non aggiornati in memcached. Penso che tu abbia scelto l'approccio giusto, ovvero: aggiorna il DB.

In ogni caso, avrai bisogno di un wrapper sul tuo aggiornamento DB (che hai fatto). Il tuo codice per aggiornare l'utente nel DB e in-RAM dovrebbe anche fare un push per memcached, OPPURE una scadenza in memcached.

Ad esempio: se gli utenti eseguono normalmente un aggiornamento una volta per sessione come parte della disconnessione, non c'è molto altro da aggiornare i dati nella cache (ad es. alto punteggio totale) - dovresti scadere subito.

SE comunque aggiorneranno i dati (es. stato attuale del gioco) e quindi dopo 0,2 secondi avrai un colpo di pagina PHP immediato che richiederà i dati, lo vorrai fresco nella cache.

    
risposta data 06.01.2012 - 12:16
fonte
3

Non vorrei parlarne come hai delineato. Quello che devi fare è decidere se hai effettivamente BISOGNO di dati completamente aggiornati. Quindi, se ne hai bisogno, decidi quali parti dei dati devono essere sempre aggiornate e separale da quelle che possono essere memorizzate nella tua architettura.

Ad esempio, probabilmente si desidera aggiornare l'indirizzo e-mail dell'utente non appena vengono modificati, quindi non si inviano messaggi all'indirizzo sbagliato, ma è improbabile che la data di nascita o il cognome dell'utente sia necessaria per essere completamente aggiornato per offrire un'esperienza utente decente. (N.B. Non sto usando un esempio di architettura di gioco perché non so a che tipo di gioco puntare, e penso che questo sia abbastanza facile da capire).

In questo modo hai due insiemi di dati chiari: dati memorizzabili nella cache a breve e lungo termine. Probabilmente si può ottenere una durata della cache di un minuto circa sui dati a breve termine, solo per alleggerire il carico sul DB, ma i dati a lungo termine possono essere lasciati nella cache su una durata scorrevole per tutto il tempo che è usato.

Quindi devi gestire gli aggiornamenti. Per prima cosa, dovrei utilizzare un trigger DB per rimuovere semplicemente gli elementi dalla cache una volta scaduti. Questo costringerà il tuo livello aziendale ad attivare un aggiornamento della cache alla successiva richiesta dei dati, liberando un po 'di spazio nella cache se i dati non vengono utilizzati (ad esempio se un utente cambia il proprio indirizzo e-mail e si disconnette immediatamente) . Se ciò causerà problemi di prestazioni nell'interfaccia utente (ad esempio, introdurrà un ritardo eccessivo durante l'attesa per gli aggiornamenti della cache), sarà quindi sufficiente attivare la chiamata della cache una volta rimosso l'elemento dalla cache. Guarderei anche all'ottimizzazione dei tempi di lettura del DB per questo piccolo insieme di dati, per garantire che qualsiasi ritardo indotto nell'aggiornare la cache sia minimo (questo dovrebbe essere più semplice in quanto è sufficiente caricare i dati di cui si ha realmente bisogno).

Quello che non farei, in nessuna circostanza, è aggiungere un ulteriore metodo per riempire la cache, poiché in questo caso dovrai mantenere la chiamata (e gli hook dell'API, ecc.) in due punti.

Per quanto riguarda i getchas, la cosa principale che devi fare attenzione se stai scrivendo direttamente nella cache è la sincronizzazione. Se molti thread tentano di leggere mentre stai eseguendo l'aggiornamento silenzioso, potresti avere alcuni gravi problemi di dati non validi, il che impedirà il tentativo di mantenere i dati aggiornati in primo luogo.

    
risposta data 06.01.2012 - 12:30
fonte

Leggi altre domande sui tag