Strategie di memorizzazione nella cache per entità e raccolte

6

Al momento disponiamo di un framework applicativo in cui memorizziamo automaticamente sia le entità che le raccolte di entità a livello aziendale (utilizzando la cache .NET). Quindi il metodo GetWidget (int id) controlla la cache utilizzando una chiave Widget_Id_ {0} prima di colpire il database e il metodo GetWidgetsByStatusId (int statusId) controlla la cache utilizzando Widgets_Collections_ByStatusId_ {0}. Se gli oggetti non sono nella cache, vengono recuperati dal database e aggiunti alla cache.

Questo approccio è ovviamente veloce per gli scenari di lettura, e poiché un approccio globale è veloce da implementare, ma richiede un numero elevato di chiavi di cache da eliminare quando le operazioni CRUD vengono eseguite sulle entità. Ovviamente, con l'aggiunta di metodi aggiuntivi, questo impatta le prestazioni e diminuiscono i vantaggi del caching.

Sono interessato ad approcci alternativi alla gestione della memorizzazione nella cache delle raccolte. So che NHibernate memorizza nella cache una lista degli identificatori nella raccolta piuttosto che le entità reali. È un approccio che altre persone hanno provato: quali sono i pro e i contro?

In particolare, sto cercando opzioni che ottimizzino le prestazioni e possano essere implementate automaticamente attraverso il codice generato da boilerplate (abbiamo il nostro strumento di generazione del codice). So che alcune persone diranno che il caching deve essere fatto a mano ogni volta per soddisfare le esigenze della situazione specifica, ma sto cercando qualcosa che ci farà ottenere la maggior parte del modo automaticamente.

    
posta Rob West 19.06.2012 - 17:07
fonte

1 risposta

8

Ho sperimentato diversi approcci al caching degli oggetti e vedo i vantaggi di un approccio in cui le raccolte sono memorizzate nella cache come riferimenti anziché come oggetti reali.

Un esempio:

User GetUser(int ID);
ICollection<User> GetRecentUsers(int amount);
ICollection<User> GetActiveUsers(int amount);
void Update(User user);

In questo esempio, se tutti e tre i metodi "Get" caricano, memorizzano nella cache e restituiscono i dati utente effettivi, i dati andranno inattivi ogni volta che viene effettuato un aggiornamento a un oggetto contenuto in una delle raccolte.

Delega della responsabilità della cache

Flushing ogni volta che si esegue un aggiornamento, tuttavia, si verificherà una cache piuttosto inutile. Quindi hai bisogno di un modo per sapere cosa è andato stantio. Sfortunatamente, tenere traccia di questo non è un compito facile.

Invece di cercare di tenere traccia dei dati in cui si trova, è possibile creare uno schema in cui si delegano la gestione dei dati e si mantiene la logica della cache in un unico posto.

Nell'esempio sopra GetUser (int ID) potrebbe essere l'unico metodo consentito per caricare e memorizzare nella cache gli oggetti utente.

GetRecentUsers () e GetActiveUsers () sarebbero quindi responsabili del caricamento solo di un elenco di ID utente e chiamano GetUser () per popolare effettivamente una raccolta di utenti prima di restituire il risultato.

In questo modo, quando aggiorni un oggetto utente, devi solo invalidare esattamente un oggetto memorizzato nella cache.

L'elenco di ID detenuto da GetRecentUsers verrà invalidato solo quando un nuovo utente si unisce al sito ecc.

Questo ti dà un approccio più pulito per mantenere la cache in ordine. Tuttavia presenta i propri problemi di impostazione.

insidie

Se inizi con una cache fredda e carichi i 10 utenti più recenti, avrai un problema N + 1 nelle tue mani. In pratica, esegui una query per recuperare l'elenco di utenti e 10 query aggiuntive per popolare la cache.

Questo può essere un grosso problema a seconda dei dati e dell'impostazione. Puoi comunque prendere misure contro questi problemi eseguendo il preriscaldamento della cache o consentendo operazioni batch (che introducono di nuovo complessità).

Non c'è un proiettile d'argento. Ma trovo l'approccio della delegazione utile quando implementato con cura.

    
risposta data 19.06.2012 - 18:32
fonte

Leggi altre domande sui tag