2012-11-27 6 views
12

Qualcuno ha qualche idea o riferimenti su come implementare uno strato di persistenza dei dati che utilizza sia un localStorage e REST di archiviazione remota:Architettura per lo strato di dati che utilizza sia localStorage e un server remoto REST

I dati di una certa il client è memorizzato con localStorage (utilizzando una scheda indexedDB ember-data). I dati memorizzati localmente vengono sincronizzati con il server remoto (utilizzando RESTadapter ember-data).

Il server raccoglie tutti i dati dai client. Utilizzando mathematical sets notazione:

Server = Client1 ∪ Client2 ∪ ... ∪ ClientN 

dove, in generale, qualsiasi record non può essere unica per un determinato cliente:

ClientX ∩ ClientY ≠ 0, ∀ X,Y ∈ [1,N] 

Ecco alcuni scenari:

  • Un client crea una disco. L'ID del record non può essere impostato sul client, poiché potrebbe entrare in conflitto con un record memorizzato sul server. Pertanto un record appena creato deve essere impegnato sul server -> ricevere l'id -> creare il record in localStorage.

  • Un record viene aggiornato sul server e, di conseguenza, i dati in localStorage e nel server non sono sincronizzati. Solo il server sa che, così l'architettura ha bisogno di implementare un'architettura push (?)

useresti 2 negozi (uno per localStorage, uno per il riposo) e la sincronizzazione tra di loro, o utilizzare un IndexedDB ibrido/Adattatore REST e scrivere il codice di sincronizzazione all'interno dell'adattatore?

Riesci a vedere un modo per evitare l'implementazione di push (Web Sockets, ...)?

+0

Questo articolo fornisce alcune informazioni: http://engineering.linkedin.com/mobile/linkedin-ipad-using-local-storage-snappy-mobile-apps –

risposta

7

Il problema che si presenta non può essere risolto in alcuni paragrafi, o semplicemente risposto. Tuttavia, ecco la mia prova ...

In primo luogo, ci sono serie di difficoltà con l'approccio che abbiamo adottato:

  1. I clienti devono essere sempre di rete collegati per creare dati e ricevere le chiavi dal server .
  2. Se si creano diversi negozi (locale & REST), tutto il codice dell'applicazione che richiede i dati deve essere visualizzato in entrambi i negozi. Ciò aumenta in modo significativo la complessità di ogni parte dell'applicazione.
  3. Dopo aver creato una riga, se si desidera creare righe figlio, è necessario attendere che il server restituisca la chiave primaria prima di poterla fare riferimento come chiave esterna nella riga secondaria. Per qualsiasi struttura di dati moderatamente complessa, questo diventa un onere pesante.
  4. Quando il server si arresta, tutti i client non possono creare dati.

Ecco il mio approccio. Utilizza SequelSphereDB, ma la maggior parte dei concetti può essere riutilizzata attraverso altri sistemi di gestione dei dati dei clienti.

PRIMO: utilizzare gli UUID per le chiavi primarie.

La maggior parte dei sistemi di gestione dei dati client deve fornire un modo per generare ID univoci universalmente.SequelSphere lo fa semplicemente con una funzione SQL: UUID(). Avere un UUID come chiave primaria per ogni riga consente di generare chiavi primarie su qualsiasi client in qualsiasi momento senza dover contattare il server e garantire comunque che gli ID siano univoci. Ciò consente inoltre all'applicazione di funzionare in modalità "offline", senza richiedere una connessione al server durante l'esecuzione. Ciò impedisce anche a un server abbattuto di abbattere tutti i client.

SECONDA: utilizzare un singolo set di tabelle che rispecchiano il server.

Questo è più un requisito per semplicità che altro. È anche un requisito per i prossimi due principi fondamentali.

TERZO: per la sincronizzazione verso il basso di piccoli set di dati, è preferibile aggiornare completamente i dati del client dal server.

Se possibile, eseguire aggiornamenti completi dei dati sul client dal server. È un paradigma più semplice e comporta meno problemi di integrità dei dati interni. Lo svantaggio principale è la dimensione dei dati nel trasferimento.

QUARTO: Per verso il basso la sincronizzazione di dati di grandi dimensioni, effettuare gli aggiornamenti 'transazionale'

Questo è dove il mio approccio diventa un po 'più complessa. Se i set di dati sono troppo grandi e richiedono solo la sincronizzazione delle righe da sincronizzare, è necessario trovare un modo per sincronizzarli in base alle "transazioni". Ovvero: gli inserimenti/aggiornamenti/eliminazioni nell'ordine in cui sono stati eseguiti sul server per fornire un semplice script per l'esecuzione degli stessi sul client.

È preferibile avere una tabella sul server che registra le transazioni da sincronizzare sul dispositivo. Se questo non è possibile, l'ordine può spesso essere registrato sul server utilizzando Timestamp sulle righe e chiedere al cliente tutte le modifiche da un determinato timestamp. Big Negative: dovrai tenere traccia delle righe cancellate tramite cancellazioni "logiche" o rintracciarle nella loro tabella. Ancora, isolare la complessità del server è preferibile alla sua diffusione su tutti i client.

Quinto: Per l'alto-sincronizzazione, l'uso 'transazionali' aggiornamenti

Questo è dove SequelSphereDB brilla davvero: Si terrà traccia per voi di tutti gli inserimenti, aggiornamenti ed eliminazioni eseguite contro tavoli, e poi restituiscili al momento della sincronizzazione. Lo fa anche attraverso il riavvio del browser, dal momento che persiste le informazioni in localstorage/indexeddb. Gestisce anche commit e rollback in modo appropriato. L'app client può interagire con i dati come farebbe normalmente senza dover riflettere sulla registrazione delle modifiche, quindi utilizzare "Change Trackers" di SequelSphereDB per riprodurre le modifiche al momento della sincronizzazione.

Se si usa SequelSphere (si dovrebbe essere), quindi mantenere una tabella separata sul client per registrare tutti gli inserimenti, gli aggiornamenti e le eliminazioni eseguite dal client. Ogni volta che l'applicazione client inserisce/aggiorna/elimina righe, creane una copia nella tabella "transazione". Al momento della sincronizzazione ascendente, invia quelli. Sul server, è sufficiente eseguire gli stessi passaggi nello stesso ordine per replicare i dati presenti sul client.

ANCHE IMPORTANTE: eseguire sempre una sincronizzazione in avanti prima di aggiornare completamente le tabelle client dal server.:)

Conclusione

Io suggerisco di andare per la semplicità alla complessità in più posti possibili. Usare UUID per chiavi primarie è estremamente utile per questo. Anche l'utilizzo di una sorta di "change tracker" è molto utile. Utilizzare uno strumento come SequelSphereDB per tracciare le modifiche per te è molto utile, ma non necessario per questo approccio.

INFORMATIVA COMPLETA: sono strettamente correlata alla società SequelSphere, ma tale prodotto non è realmente necessario per l'implementazione dell'approccio di cui sopra.

+0

Grazie John, grandi intuizioni. Ho iniziato a implementare un prototipo e sono arrivato a (più o meno) le stesse conclusioni di te. Ma tu li hai giustificati meglio :) Tuttavia, non sono sicuro che sia necessario registrare ogni modifica di un record sul client. Le modifiche dei record non sono ** memoryless **? In questo, hai solo bisogno di conoscere l'ultimo stato del record. Quello che ho fatto è creare una tabella 'unsynced' sul client e memorizzare tutti i record che sono stati modificati e non ancora impegnati sul server. Una volta che un record è impegnato e sincronizzato con il server, viene rimosso da 'unsynced'. Ci sono degli svantaggi con questo? –

+0

In effetti la creazione di ID sul client è la strada da percorrere. Uno svantaggio è che Javascript non può generare ID univoci globali, come indicato qui http://stackoverflow.com/a/105074/359104. Ma naturalmente, questo può essere superato avendo il server convalidare id e restituire immediatamente eventuali ID modificati. –

+1

Per quanto riguarda le modifiche senza memoria: tutto dipende dai dati. A volte la creazione di righe figlio richiede che le righe padre abbiano valori particolari. O per dirla in altro modo: il modo più semplice per mantenere l'integrità referenziale (RI) in un insieme complesso di oggetti è semplicemente "riprodurre" gli inserimenti, gli aggiornamenti e le eliminazioni avvenute sul client. Spesso si tratta di dati e di lavoro pochissimi e viene fornito con il vantaggio della semplicità. Determinare le righe modificate è molto più difficile che registrare le modifiche nel momento in cui si verificano. Il tuo approccio all'idea di avere un tavolo o dei cambiamenti suona bene. –

Problemi correlati