Ho creato un sistema come questo per un'app circa 8 anni fa e posso condividere un paio di modi in cui si è evoluta man mano che l'utilizzo dell'app è cresciuto.
Ho iniziato registrando ogni modifica (inserire, aggiornare o eliminare) da qualsiasi dispositivo in una tabella "cronologia". Pertanto, se, ad esempio, qualcuno modifica il proprio numero di telefono nella tabella "contatto", il sistema modificherà il campo contact.phone e aggiungerà anche un record cronologico con action = update, field = phone, record = [ID contatto], valore = [nuovo numero di telefono]. Quindi, ogni volta che un dispositivo si sincronizza, scarica gli elementi della cronologia dall'ultima sincronizzazione e li applica al suo database locale. Questo suona come il modello di "replica delle transazioni" sopra descritto.
Un problema è mantenere gli ID univoci quando è possibile creare oggetti su dispositivi diversi. Non sapevo degli UUID quando ho iniziato questo, quindi ho usato gli ID a incremento automatico e ho scritto un codice contorto che viene eseguito sul server centrale per controllare i nuovi ID caricati dai dispositivi, cambiarli in un ID univoco in caso di conflitto e dire al dispositivo di origine di modificare l'ID nel suo database locale. Il solo cambiamento degli ID dei nuovi record non era poi così male, ma se creo, ad esempio, un nuovo elemento nella tabella dei contatti, quindi creo un nuovo elemento correlato nella tabella degli eventi, ora ho chiavi esterne che devo anche controlla e aggiorna.
Alla fine ho appreso che gli UUID potevano evitarlo, ma a quel punto il mio database stava diventando piuttosto grande e temevo che un'implementazione UUID completa avrebbe creato un problema di prestazioni. Quindi, invece di utilizzare UUID completi, ho iniziato a utilizzare chiavi alfanumeriche di 8 caratteri generate in modo casuale come ID e ho lasciato il mio codice esistente in atto per gestire i conflitti. Da qualche parte tra le mie attuali chiavi di 8 caratteri e i 36 caratteri di un UUID ci deve essere un punto debole che eliminerebbe i conflitti senza inutile gonfiamento, ma dal momento che ho già il codice di risoluzione dei conflitti, non è stata una priorità sperimentare con quello .
Il problema successivo era che la tabella della cronologia era circa 10 volte più grande dell'intero resto del database. Questo rende lo stoccaggio costoso e qualsiasi manutenzione nella tabella della cronologia può essere dolorosa. Mantenere l'intera tabella consente agli utenti di ripristinare qualsiasi modifica precedente, ma ciò ha iniziato a sembrare eccessivo. Quindi ho aggiunto una routine al processo di sincronizzazione in cui se l'elemento della cronologia che un dispositivo ha scaricato l'ultima volta non esiste più nella tabella della cronologia, il server non gli fornisce gli elementi della cronologia recente, ma invece gli fornisce un file contenente tutti i dati per quell'account. Quindi ho aggiunto un cronjob per eliminare gli elementi della cronologia più vecchi di 90 giorni. Ciò significa che gli utenti possono comunque ripristinare le modifiche di meno di 90 giorni e, se si sincronizzano almeno una volta ogni 90 giorni, gli aggiornamenti saranno incrementali come prima. Ma se aspettano più di 90 giorni,
Questa modifica ha ridotto le dimensioni della tabella della cronologia di quasi il 90%, quindi ora la manutenzione della tabella della cronologia rende il database solo due volte più grande invece di dieci volte più grande. Un altro vantaggio di questo sistema è che la sincronizzazione potrebbe ancora funzionare senza la tabella cronologica, se necessario, come se avessi bisogno di un po 'di manutenzione che lo metteva temporaneamente offline. Oppure potrei offrire diversi periodi di rollback per gli account a prezzi diversi. E se ci sono più di 90 giorni di modifiche da scaricare, il file completo è generalmente più efficiente del formato incrementale.
Se dovessi ricominciare da capo oggi, salterei il controllo dei conflitti ID e mirerei solo a una lunghezza della chiave sufficiente per eliminare i conflitti, con un qualche tipo di controllo degli errori nel caso. Ma la tabella della cronologia e la combinazione di download incrementali per gli aggiornamenti recenti o un download completo quando necessario ha funzionato bene.