Memorizzazione nella cache dei risultati impaginati, eliminazione dell'aggiornamento: come risolvere?

StackOverflow https://stackoverflow.com/questions/109480

Domanda

Ho creato un forum e stiamo implementando una soluzione di memorizzazione nella cache apc e memcache per salvare un po 'di lavoro nel database.

Ho iniziato a implementare il livello cache con chiavi come " Categorie :: getAll " ;, e se avessi dati specifici dell'utente, aggiungerei le chiavi con elementi come l'ID utente, in modo da ottenere " utente :: getFavoriteThreads | 1471 " . Quando un utente aggiungeva un nuovo thread preferito, eliminavo la chiave della cache e ricreava la voce.

Tuttavia, e qui arriva il problema:

Volevo memorizzare nella cache i thread in un forum. Abbastanza semplice, " Forum :: getThreads | $ iForumId " ;. Ma ... Con l'impaginazione, dovrei dividerlo in diverse voci della cache, ad esempio

"Forum::getThreads|$iForumId|$iLimit|$iOffset".

Va ??bene, fino a quando qualcuno non pubblica una nuova discussione nel forum. Ora dovrò eliminare tutte le chiavi in ?? " Forum :: getThreads | $ iForumId " , qualunque sia il limite e l'offset.

Quale sarebbe un buon modo per risolvere questo problema? Preferirei davvero non superare tutti i limiti e gli offset possibili finché non trovo qualcosa che non corrisponde più.

Grazie.

È stato utile?

Soluzione

Potresti anche voler dare un'occhiata al costo di archiviazione dei dati della cache, in termini di impegno e costo della CPU, rispetto a come ciò che la cache ti acquisterà.

Se ritieni che l'80% delle visualizzazioni del tuo forum stia osservando la prima pagina dei thread, puoi decidere di memorizzare nella cache solo quella pagina. Ciò significherebbe che sia le letture che le scritture della cache sono molto più semplici da implementare.

Allo stesso modo con l'elenco dei thread preferiti di un utente. Se questo è qualcosa che ogni persona visita raramente, la cache potrebbe non migliorare troppo le prestazioni.

Altri suggerimenti

Solo un aggiornamento: Ho deciso che il punto di Josh sull'uso dei dati era molto buono. È improbabile che le persone continuino a visualizzare la pagina 50 di un forum.

Sulla base di questo modello, ho deciso di memorizzare nella cache gli ultimi 90 thread in ogni forum. Nella funzione di recupero controllo il limite e l'offset per vedere se la sezione di thread specificata è all'interno della cache o meno. Se rientra nel limite della cache, utilizzo array_slice () per recuperare la parte giusta e restituirla.

In questo modo, posso usare una sola chiave cache per forum e ci vuole pochissimo sforzo per cancellare / aggiornare la cache :-)

Vorrei anche sottolineare che in altre domande più pesanti, sono andato con il modello di flungabunga, memorizzando le relazioni tra le chiavi. Sfortunatamente Stack Overflow non mi consente di accettare due risposte.

Grazie!

Sono riuscito a risolvere questo problema estendendo la classe memcache con una classe personalizzata (diciamo ExtendedMemcache) che ha una proprietà protetta che conterrà una tabella hash di gruppo ai valori chiave.

Il metodo ExtendedMemcache- > set accetta 3 args ( $ strGroup , $ strKey , $ strValue ) Quando chiami set, memorizzerà la relazione tra $ strGroup e $ strKey , nella proprietà protetta e poi continuerà a memorizzare $ strKey a $ strValue in memcache .

Puoi quindi aggiungere un nuovo metodo alla classe ExtendedMemcache chiamato " deleteGroup " ;, che, una volta passata una stringa, troverà le chiavi associate a quel gruppo e eliminerà a turno ciascuna chiave.

Sarebbe qualcosa del genere: http://pastebin.com/f566e913b Spero che tutto ciò abbia senso e risolva per te.

PS. Suppongo che se si desidera utilizzare chiamate statiche, la proprietà protetta potrebbe essere salvata in memcache stessa con la propria chiave. Solo un pensiero.

Stai essenzialmente cercando di memorizzare nella cache una vista, che diventerà sempre complicata. Dovresti invece provare a memorizzare nella cache solo i dati, perché i dati cambiano raramente. Non memorizzare nella cache un forum, memorizzare nella cache le righe del thread. Quindi la tua chiamata db dovrebbe solo restituire un elenco di ID, che hai già nella tua cache. La chiamata db si alleggerirà rapidamente su qualsiasi tabella MyISAM, e quindi non dovrai fare un grande join, che mangia memoria db.

Una possibile soluzione non è impaginare la cache dei thread in un forum, ma piuttosto inserire le informazioni sul thread in Forum :: getThreads | $ iForumId . Quindi nel tuo codice PHP estrai solo quelli che desideri per quella determinata pagina, ad esempio

$page = 2;
$threads_per_page = 25;
$start_thread = $page * $threads_per_page;

// Pull threads from cache (assuming $cache class for memcache interface..)
$threads = $cache->get("Forum::getThreads|$iForumId");

// Only take the ones we need
for($i=$start_thread; $i<=$start_thread+$threads_per_page; $i++)
{
    // Thread display logic here...
    showThread($threads[$i]);
}

Ciò significa che hai un po 'più di lavoro da fare per estrarli su ogni pagina, ma ora devi solo preoccuparti di invalidare la cache in un posto sull'aggiornamento / aggiunta del nuovo thread.

flungabunga: La tua soluzione è molto vicina a ciò che sto cercando. L'unica cosa che mi impedisce di farlo è dover archiviare le relazioni in memcache dopo ogni richiesta e ricaricarle.

Non sono sicuro di quanto significherebbe un colpo di performance, ma sembra un po 'inefficiente. Farò alcuni test e vedrò come si espande. Grazie per un suggerimento strutturato (e del codice da mostrare, grazie!).

Stai molto attento a fare questo tipo di ottimizzazione senza avere fatti concreti su cui misurare.

La maggior parte dei database ha diversi livelli di cache. Se questi sono ottimizzati correttamente, il database probabilmente farà un lavoro molto migliore nella memorizzazione nella cache, di quanto tu possa fare da solo.

In risposta a flungabunga:

Un altro modo per implementare il raggruppamento è quello di inserire il nome del gruppo più un numero di sequenza nelle chiavi stesse e incrementare il numero di sequenza in "cancella". il gruppo. Memorizzi l'attuale numero di sequenza valido per ciascun gruppo nella sua chiave.

per es.

get seqno_mygroup
23

get mygroup23_mykey
<mykeydata...>
get mygroup23_mykey2
<mykey2data...>

Quindi per " cancellare " il gruppo semplicemente:

incr seqno_mygroup

Voila:

get seqno_mygroup
24

get mygroup24_mykey
...empty

etc ..

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top