Memorizzazione nella cache NDB

NDB gestisce le cache per te. Esistono due livelli di memorizzazione nella cache: una cache in-context e un gateway al servizio di memorizzazione nella cache standard di App Engine, memcache. Entrambe le cache sono abilitate per impostazione predefinita per tutti i tipi di entità, ma possono essere configurate in base alle esigenze avanzate. Inoltre, NDB implementa una funzionalità chiamata batch automatico, che cerca di raggruppare le operazioni per ridurre al minimo i round trip del server.

Introduzione

La memorizzazione nella cache è utile per la maggior parte dei tipi di applicazioni. NDB memorizza automaticamente nella cache i dati che scrive o legge (a meno che un'applicazione non lo configuri in modo diverso). La lettura dalla cache è più veloce rispetto alla lettura da Datastore.

Puoi modificare il comportamento della memorizzazione nella cache di molte funzioni NDB passando gli argomenti Opzioni contesto. Ad esempio, potresti chiamare key.get(use_cache=False, use_memcache=False) per bypassare la memorizzazione nella cache. Puoi anche modificare il criterio di memorizzazione nella cache predefinito in un contesto NDB come descritto di seguito.

Attenzione: quando utilizzi lo strumento di visualizzazione di Datastore della Console di amministrazione per modificare i contenuti di Datastore, i valori memorizzati nella cache non verranno aggiornati. Di conseguenza, la cache potrebbe non essere coerente. Generalmente non è un problema per la cache contestuale. Per Memcache, ti consigliamo di utilizzare la Console di amministrazione per svuotare la cache.

Oggetti di contesto

La gestione della cache utilizza una classe denominata Context: ogni thread e ogni transazione viene eseguita in un contesto. Poiché ogni richiesta HTTP in entrata avvia un nuovo thread, ogni richiesta viene eseguita con nuovo contesto. Per accedere al contesto attuale, usa la funzione ndb.get_context().

Attenzione: non ha senso condividere Context oggetti tra più thread o richieste. Non salvare il contesto come variabile globale. È sufficiente memorizzarlo in una variabile locale o locale del thread.

Gli oggetti Context dispongono di metodi per impostare i criteri della cache e manipulare la cache in altro modo.

La cache in-context

La cache in-context persiste solo per la durata di un singolo thread. Ciò significa che a ogni richiesta HTTP in entrata viene assegnata una nuova cache in-context ed è "visibile" solo al codice che gestisce la richiesta. Se la tua applicazione genera thread aggiuntivi durante la gestione di una richiesta, questi thread avranno anche una nuova cache in-context separata.

La cache in-context è veloce e si trova in memoria. Quando una funzione NDB scrive Datastore, inoltre scrive nella cache contestuale. Quando una funzione NDB legge un'entità, controlla prima la cache contestuale. Se l'entità viene trovata lì, non viene eseguita alcuna interazione con Datastore.

Quando una funzione NDB esegue una query su Datastore, l'elenco dei risultati viene recuperato da per il datastore. Tuttavia, se un singolo risultato si trova nella cache contestuale, viene utilizzato al posto del valore recuperato dalla query Datastore. I risultati della query vengono riscritti nella cache contestuale se lo è (ma mai a Memcache).

Quando si eseguono query a lunga esecuzione in attività in background, è possibile che la cache contestuale per consumare grandi quantità di memoria. Questo perché la cache conserva una copia di ogni entità recuperata o archiviata nel contesto corrente. Per evitare eccezioni di memoria nelle attività che richiedono molto tempo, puoi disattivare la cache o impostare un criterio che escluda le entità che consumano più memoria.

Memcache

Memcache è il servizio di memorizzazione nella cache standard di App Engine, più veloce di Datastore, ma più lenta della cache contestuale (millisecondi contro microsecondi).

Per impostazione predefinita, un contesto non transazionale memorizza nella cache tutte le entità in memcache. Tutti i contesti di un'applicazione usare lo stesso server memcache e vedere un insieme coerente di valori memorizzati nella cache.

Memcache non supporta le transazioni. Pertanto, un aggiornamento da applicare sia Datastore e memcache possono essere create solo per uno dei due. Per mantenere la coerenza in questi casi (eventualmente a spese delle prestazioni), l'entità aggiornata viene eliminata da Memcache e poi scritta in Datastore. Un'operazione di lettura successiva troverà l'entità mancante in memcache, la recupererà da Datastore e poi la aggiornerà in memcache come effetto collaterale della lettura. Inoltre, NDB legge all'interno delle transazioni ignorando la memcache.

Quando le entità vengono scritte all'interno di una transazione, memcache non viene utilizzato. Quando la transazione viene confermata, il relativo contesto tenterà di eliminare tutte queste entità da memcache. Tieni presente, tuttavia, che errori che potrebbero impedire tali eliminazioni.

Funzioni relative ai criteri

La memorizzazione nella cache automatica è comoda per la maggior parte delle applicazioni, ma forse la tua applicazione è insolita e vuoi disattivare la memorizzazione nella cache automatica per alcune o tutte le entità. Puoi controllare il comportamento delle cache impostando le funzioni di criteri. Esiste una funzione di criteri per la cache in-process, impostata con

context = ndb.get_context()
context.set_cache_policy(func)

e un'altra per memcache, impostata con

context = ndb.get_context()
context.set_memcache_policy(func)

Ogni funzione dei criteri accetta una chiave e restituisce un risultato booleano. Se restituisce False, l'entità identificata non verrà salvata nella cache corrispondente. Ad esempio, per bypassare la cache in-process per tutte le entità Account, puoi scrivere

context = ndb.get_context()
context.set_cache_policy(lambda key: key.kind() != 'Account')

Tuttavia, continua a leggere per scoprire un modo più semplice per ottenere lo stesso risultato. Per comodità, puoi passare True o False instead of a function that always returns the same value. I criteri predefiniti memorizzano nella cache tutte le entità.

Esiste anche una funzione dei criteri Datastore che stabilisce quali entità vengono scritte nel datastore:

context = ndb.get_context()
context.set_datastore_policy(func)

Funziona come le funzioni dei criteri della cache in-context e memcache: se la funzione del criterio Datastore restituisce False per una determinata chiave, l'entità corrispondente non verrà scritta in Datastore. Potrebbe essere scritto nella cache in-process o in memcache se le relative funzioni di criteri lo consentono. Questo può essere utile nei casi in cui hai dati simili a entità che vuoi memorizzare nella cache, ma che non devi archiviare in Datastore. Come per i criteri della cache, puoi passare True o False invece di una funzione che restituisce sempre lo stesso valore.

Memcache scade automaticamente gli elementi quando la memoria è sotto pressione. Puoi impostare una funzione del criterio di timeout memcache per determinare durata massima dell'entità nella cache:

context = ndb.get_context()
context.set_memcache_timeout_policy(func)

Questa funzione viene chiamata con un argomento chiave e deve restituire un numero intero che specifica la durata massima in secondi; 0 o None significa indefinito (purché il server memcache abbia memoria sufficiente). Per comodità, puoi semplicemente passare una costante intera anziché una funzione che restituisce sempre lo stesso valore. Per ulteriori informazioni sui timeout, consulta la documentazione relativa alle memcache.

Nota: Non esiste un criterio di durata distinto per la cache contestuale: la durata della cache è uguale a quella del suo contesto, una singola richiesta HTTP in entrata. Tuttavia, puoi svuotare la cache in-process chiamando
context = ndb.get_context()
context.clear_cache()

Un contesto completamente nuovo inizia con una cache in-process vuota.

Anche se le funzioni dei criteri sono molto flessibili, Nella pratica, la maggior parte dei criteri è semplice. Ad esempio,

  • Non memorizzare nella cache entità che appartengono a una specifica classe di modello.
  • Imposta il timeout di memcache per le entità in questa classe di modello su 30 secondi.
  • Le entità in questa classe di modello non devono essere scritte in Datastore.

Per evitare di dover scrivere e aggiornare continuamente funzioni dei criteri (o, peggio ancora, eseguire l'override dei criteri per utilizzando le opzioni di contesto), le funzioni predefinite del criterio ottenere la classe del modello dalla chiave passata e cerca variabili di classe specifiche nella classe del modello:

Variabile classe Tipo Descrizione
_use_cache bool Specifica se memorizzare le entità nella cache in-process; sostituisce il criterio della cache in-process predefinito.
_use_memcache bool Specifica se memorizzare le entità in memcache; sostituisce il criterio memcache predefinito.
_use_datastore bool Specifica se archiviare le entità nel datastore; sostituisce il criterio Datastore predefinito.
_memcache_timeout int Durata massima delle entità in memcache; sostituisce il criterio di timeout memcache predefinito.

Nota: Si tratta di una funzionalità della funzione dei criteri predefiniti per ogni criterio. Se specifichi la tua funzione per le norme, ma vuoi anche ricorrere alla per il criterio predefinito, richiama esplicitamente le funzioni del criterio predefinito come metodi statici della classe Context:

  • default_cache_policy(key)
  • default_memcache_policy(key)
  • default_datastore_policy(key)
  • default_memcache_timeout_policy(key)