Strutturazione dei dati per una coerenza elevata

Nota: Gli sviluppatori che creano nuove applicazioni sono vivamente incoraggiati a utilizzare il Libreria client NDB, che offre numerosi vantaggi rispetto a questa libreria client, come la memorizzazione automatica nella cache delle entità tramite API. Se al momento utilizzi la libreria client DB precedente, leggi il Guida alla migrazione da database a NDB

Datastore offre disponibilità elevata, scalabilità e durabilità la distribuzione dei dati su molte macchine e l'uso la replicazione su un'ampia area geografica. Tuttavia, c'è un compromesso progettazione, ovvero la velocità effettiva di scrittura per qualsiasi gruppo di entità è limitato a circa un commit al secondo ed esistono limitazioni per le query o le transazioni che in più gruppi di entità. In questa pagina vengono descritte le limitazioni e illustra le best practice per strutturare i dati in modo da supportare e la coerenza, soddisfacendo al contempo la velocità effettiva di scrittura dell'applicazione i tuoi requisiti.

Le letture altamente coerenti restituiscono sempre i dati correnti e, se eseguite all'interno di un di transazioni, sembreranno provenire da un'unica istantanea coerente. Tuttavia, Le query devono specificare un filtro predecessore per essere partecipano a una transazione e le transazioni possono riguardare al massimo 25 persone giuridiche gruppi. Le letture coerenti alla fine non hanno queste limitazioni e sono adeguato in molti casi. L'utilizzo di letture coerenti alla fine consente di distribuire i dati tra un numero maggiore di gruppi di entità, in modo da di ottenere una velocità effettiva di scrittura maggiore eseguendo i commit in parallelo gruppi di entità diversi. Ma è necessario comprendere le caratteristiche letture coerenti per determinare se sono adatte la tua applicazione:

  • I risultati di queste letture potrebbero non riflettere le ultime transazioni. Questo perché queste letture non assicurano che la replica sia in esecuzione su sia aggiornato. Utilizzano invece qualsiasi dato disponibile su quella replica al momento dell'esecuzione della query. La latenza di replica è quasi sempre inferiore a per alcuni secondi.
  • Una transazione impegnata che ha interessato più entità potrebbe sembrare è stato applicato ad alcune entità e non ad altre. Tieni presente, tuttavia, che transazione non risulterà mai applicata parzialmente all'interno di un singolo dell'oggetto.
  • I risultati della query possono includere entità che non avrebbero dovuto essere incluse in base ai criteri del filtro e potrebbero escludere entità che dovrebbero avere inclusi. Questo può accadere perché gli indici potrebbero essere letti a un più elevata rispetto alla lettura dell'entità stessa.

Per capire come strutturare i dati in modo da ottenere una elevata coerenza, confronta due diversi approcci per una semplice applicazione guestbook. Il primo approccio crea una nuova entità base per ogni entità creata:

import webapp2
from google.appengine.ext import db

class Guestbook(webapp2.RequestHandler):
  def post(self):
    greeting = Greeting()
    ...

Quindi esegue una query sul tipo di entità Greeting per conoscere i dieci saluti più recenti.

import webapp2
from google.appengine.ext import db

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')
    greetings = db.GqlQuery("SELECT * "
                            "FROM Greeting "
                            "ORDER BY date DESC LIMIT 10")

Tuttavia, poiché stai utilizzando una query non predecessore, la replica utilizzata per eseguire la query in questo schema potrebbe non aver visto il nuovo saluto quando l'esecuzione della query. Ciononostante, quasi tutte le scritture saranno disponibili non predecessori entro pochi secondi dal commit. Per molte applicazioni, soluzione che fornisce i risultati di una query non predecessore nel contesto della le modifiche dell'utente corrente sono in genere sufficienti per eseguire la replica completamente accettabili.

Se per la tua applicazione è importante l'elevata coerenza, puoi adottare un approccio alternativo scrivere entità con un percorso predecessore che identifica la stessa entità base tra tutte le entità che devono essere lette in un singolo predecessore a elevata coerenza query:

import webapp2
from google.appengine.ext import db

class Guestbook(webapp2.RequestHandler):
  def post(self):
    guestbook_name=self.request.get('guestbook_name')
    greeting = Greeting(parent=guestbook_key(guestbook_name))
    ...

Potrai quindi eseguire una query da predecessore a elevata coerenza all'interno del gruppo di entità identificato dall'entità base comune:

import webapp2
from google.appengine.ext import db

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.out.write('<html><body>')
    guestbook_name=self.request.get('guestbook_name')

    greetings = db.GqlQuery("SELECT * "
                            "FROM Greeting "
                            "WHERE ANCESTOR IS :1 "
                            "ORDER BY date DESC LIMIT 10",
                            guestbook_key(guestbook_name))

Questo approccio garantisce elevata coerenza scrivendo a un singolo gruppo di entità per libro degli ospiti, ma limita anche le modifiche al libro degli ospiti a un 1 scrittura al secondo (il limite supportato per i gruppi di entità). Se la tua applicazione riscontra un maggiore utilizzo in scrittura, valuta l'uso in altri modi: ad esempio, potresti mettere i post recenti in una memcache con una scadenza e visualizzare un mix di post recenti provenienti da memcache e Datastore, oppure li potresti memorizzare nella cache in un cookie, imposta uno stato nell'URL o qualcosa di completamente diverso. L'obiettivo è trovare una soluzione di memorizzazione nella cache che fornisce i dati relativi all'utente corrente per il periodo di tempo in cui che l'utente sta pubblicando sulla tua applicazione. Ricorda che, se usi un comando GET, un predecessore query o qualsiasi operazione all'interno di una transazione, vedrai sempre dati scritti di recente.