Synchronisieren von Client-Server-Datenbanken

82

Ich suche nach allgemeinen Strategien zum Synchronisieren von Daten auf einem zentralen Server mit Clientanwendungen, die nicht immer online sind.

In meinem speziellen Fall habe ich eine Android-Telefonanwendung mit einer SQLite-Datenbank und eine PHP-Webanwendung mit einer MySQL-Datenbank.

Benutzer können Informationen zur Telefonanwendung und zur Webanwendung hinzufügen und bearbeiten. Ich muss sicherstellen, dass an einem Ort vorgenommene Änderungen überall angezeigt werden, auch wenn das Telefon nicht sofort mit dem Server kommunizieren kann.

Es geht mir nicht darum, wie Daten vom Telefon zum Server übertragen werden oder umgekehrt. Ich erwähne meine speziellen Technologien nur, weil ich beispielsweise die für MySQL verfügbaren Replikationsfunktionen nicht verwenden kann.

Ich weiß, dass das Problem der Client-Server-Datensynchronisation schon lange besteht und möchte Informationen - Artikel, Bücher, Ratschläge usw. - über Muster zur Behandlung des Problems. Ich würde gerne allgemeine Strategien für den Umgang mit Synchronisation kennenlernen, um Stärken, Schwächen und Kompromisse zu vergleichen.

Scott Saunders
quelle

Antworten:

93

Das erste, was Sie entscheiden müssen, ist eine allgemeine Richtlinie darüber, welche Seite bei widersprüchlichen Änderungen als "maßgeblich" angesehen wird.

Dh: Angenommen, Datensatz Nr. 125 wird am 5. Januar um 22 Uhr auf dem Server geändert, und derselbe Datensatz wird am 5. Januar um 23 Uhr auf einem der Telefone (nennen wir es Client A) geändert. Die letzte Synchronisierung fand am 3. Januar statt. Dann verbindet sich der Benutzer beispielsweise am 8. Januar erneut.

Das Erkennen, was geändert werden muss, ist "einfach" in dem Sinne, dass sowohl der Client als auch der Server das Datum der letzten Synchronisierung kennen. Daher muss alles, was seit der letzten Synchronisierung erstellt oder aktualisiert wurde (siehe unten für weitere Informationen), abgeglichen werden.

Angenommen, der einzige geänderte Datensatz ist # 125. Sie entscheiden entweder, dass einer der beiden automatisch "gewinnt" und den anderen überschreibt, oder Sie müssen eine Abstimmungsphase unterstützen, in der ein Benutzer entscheiden kann, welche Version (Server oder Client) die richtige ist, und die andere überschreibt.

Diese Entscheidung ist äußerst wichtig und Sie müssen die "Rolle" der Kunden abwägen. Insbesondere, wenn nicht nur zwischen Client und Server ein potenzieller Konflikt besteht, sondern auch, wenn verschiedene Clients dieselben Datensätze ändern können.

[Unter der Annahme, dass # 125 von einem zweiten Client (Client B) geändert werden kann, besteht die Möglichkeit, dass Client B, der noch nicht synchronisiert wurde, eine weitere Version desselben Datensatzes bereitstellt, wodurch die vorherige Konfliktlösung in Frage gestellt wird.]

In Bezug auf den obigen Punkt " erstellt oder aktualisiert " ... wie können Sie einen Datensatz ordnungsgemäß identifizieren, wenn er von einem der Clients stammt (vorausgesetzt, dies ist in Ihrer Problemdomäne sinnvoll)? Angenommen, Ihre App verwaltet eine Liste von Geschäftskontakten. Wenn Client A angibt, dass Sie einen neu erstellten John Smith hinzufügen müssen, und der Server einen John Smith hat, der gestern von Client D erstellt wurde ... erstellen Sie zwei Datensätze, weil Sie nicht sicher sein können, dass es sich nicht um unterschiedliche Personen handelt? Bitten Sie den Benutzer, diesen Konflikt ebenfalls zu lösen?

Haben Kunden "Eigentum" an einer Teilmenge von Daten? Dh wenn Client B als "Autorität" für Daten für Bereich 5 eingerichtet ist, kann Client A Datensätze für Bereich 5 ändern / erstellen oder nicht? (Dies würde die Lösung von Konflikten erleichtern, könnte sich jedoch für Ihre Situation als nicht durchführbar erweisen.)

Zusammenfassend sind die Hauptprobleme:

  • Definieren von "Identität" unter Berücksichtigung der Tatsache, dass getrennte Clients möglicherweise nicht auf den Server zugegriffen haben, bevor ein neuer Datensatz erstellt wurde.
  • Die vorherige Situation, unabhängig davon, wie ausgefeilt die Lösung ist, kann zu Datenverdopplungen führen. Sie müssen daher vorhersehen, wie diese regelmäßig gelöst werden können und wie Sie die Kunden darüber informieren können, dass das, was sie als "Datensatz Nr. 675" betrachten, tatsächlich mit / ersetzt durch Datensatz Nr. 543
  • Entscheiden Sie, ob Konflikte durch Fiat (z. B. "Die Serverversion übertrifft immer die des Clients, wenn die erstere seit der letzten Synchronisierung aktualisiert wurde") oder durch manuelles Eingreifen gelöst werden
  • Im Falle von Fiat , insbesondere wenn Sie entscheiden, dass der Client Vorrang hat, müssen Sie auch darauf achten, wie Sie mit anderen, noch nicht synchronisierten Clients umgehen, bei denen möglicherweise weitere Änderungen vorgenommen werden.
  • Die vorherigen Elemente berücksichtigen nicht die Granularität Ihrer Daten (um die Beschreibung zu vereinfachen). Es genügt zu sagen, dass Sie, anstatt wie in meinem Beispiel auf der Ebene "Aufzeichnen" zu argumentieren, möglicherweise besser geeignet sind, Änderungen auf Feldebene aufzuzeichnen. Oder um an einer Reihe von Datensätzen (z. B. Personendatensatz + Adressdatensatz + Kontaktdatensatz) gleichzeitig zu arbeiten und deren Aggregat als eine Art "Metadatensatz" zu behandeln.

Literaturverzeichnis:

(Die letzten drei stammen aus der digitalen ACM-Bibliothek, keine Ahnung, ob Sie Mitglied sind oder ob Sie diese über andere Kanäle erhalten können).

Von der Dr.Dobbs- Website:

  • Erstellen von Apps mit SQL Server CE und SQL RDA von Bill Wagner, 19. Mai 2004 (Best Practices zum Entwerfen einer Anwendung für den Desktop- und mobilen PC - Windows / .NET)

Von arxiv.org:

  • Ein konfliktfreier replizierter JSON-Datentyp - das Dokument beschreibt eine JSON-CRDT-Implementierung (Konfliktfreie replizierte Datentypen - CRDTs - sind eine Familie von Datenstrukturen, die gleichzeitige Änderungen unterstützen und die Konvergenz solcher gleichzeitiger Aktualisierungen gewährleisten).
p.marino
quelle
Vielen Dank für Ihre Antwort. Ich bin sehr daran interessiert, über häufig verwendete / mögliche Lösungen (Vor- und Nachteile, Vergleiche) der von Ihnen skizzierten Probleme zu lesen.
Scott Saunders
Ich nehme an, Sie haben bereits Wikipedia und die Inhalte überprüft, auf die sie verlinken, oder?
p.marino
3
+1 Dies ist ein großartiger Beitrag mit sehr wichtigen Informationen zu diesem Thema. Ein fehlender Punkt: Synchronisieren gelöschter Datensätze.
Stefan Steinegger
7
Ich neige dazu, "gelöscht" als Sonderfall von "aktualisiert" zu betrachten, insbesondere weil ich in solchen Situationen eher "logisches Löschen" als "physisches Löschen" bevorzuge. Für mich bedeutet "gelöscht" auf der Master- oder Slave-Seite mehr als alles andere "das spezielle boolesche Flag zum Löschen wurde umgedreht".
p.marino
Vielen Dank. Ich habe einen weiteren Link zu einem anderen Artikel hinzugefügt (dr.dobbs) und werde die Bibliographie aktualisieren, wenn ich etwas anderes finde.
p.marino
9

Ich würde empfehlen, dass Sie in jeder Tabelle eine Zeitstempelspalte haben und bei jedem Einfügen oder Aktualisieren den Zeitstempelwert jeder betroffenen Zeile aktualisieren. Anschließend durchlaufen Sie alle Tabellen und prüfen, ob der Zeitstempel neuer ist als der in der Zieldatenbank. Wenn es neuer ist, prüfen Sie, ob Sie es einfügen oder aktualisieren müssen.

Beobachtung 1: Beachten Sie physische Löschvorgänge, da die Zeilen aus der Quelldatenbank gelöscht werden und Sie dies auch auf der Serverdatenbank tun müssen. Sie können dieses Problem lösen, indem Sie physische Löschungen vermeiden oder alle Löschvorgänge in einer Tabelle mit Zeitstempeln protokollieren. Etwa so: DeletedRows = (id, table_name, pk_column, pk_column_value, timestamp)Also, Sie haben alle die neuen Zeilen von DeletedRows Tabelle zu lesen und einen Lösch auf dem Server mit table_name, pk_column und pk_column_value auszuführen.

Beobachtung 2: Beachten Sie FK, da das Einfügen von Daten in eine Tabelle, die sich auf eine andere Tabelle bezieht, fehlschlagen kann. Sie sollten jeden FK vor der Datensynchronisation deaktivieren.

Francisco Goldenstein
quelle
3
Uhren müssen synchron sein
bis zum
6

Wenn sich jemand mit ähnlichen Designproblemen befasst und Änderungen auf mehreren Android-Geräten synchronisieren muss, empfehle ich, Google Cloud Messaging für Android (GCM) zu überprüfen .

Ich arbeite an einer Lösung, bei der Änderungen, die an einem Client vorgenommen wurden, an andere Clients weitergegeben werden müssen. Und ich habe gerade eine Proof-of-Concept-Implementierung (Server & Client) implementiert, die wie ein Zauber funktioniert.

Grundsätzlich sendet jeder Client Delta-Änderungen an den Server. Beispielsweise hat sich die Ressourcen-ID ABCD1234 von 100 auf 99 geändert.

Der Server überprüft diese Delta-Änderungen anhand seiner Datenbank und genehmigt entweder die Änderung (Client ist synchron) und aktualisiert seine Datenbank oder lehnt die Änderung ab (Client ist nicht synchron).

Wenn die Änderung vom Server genehmigt wird, benachrichtigt der Server andere Clients (mit Ausnahme des Clients, der die Deltaänderung gesendet hat) über GCM und sendet eine Multicast-Nachricht mit derselben Deltaänderung. Clients verarbeiten diese Nachricht und aktualisieren ihre Datenbank.

Coole Sache ist, dass diese Änderungen fast sofort verbreitet werden !!! wenn diese Geräte online sind. Und ich muss auf diesen Clients keinen Abfragemechanismus implementieren.

Beachten Sie, dass GCM diese Nachricht verwirft und eine spezielle Nachricht sendet, wenn ein Gerät zu lange online ist und mehr als 100 Nachrichten in der GCM-Warteschlange auf die Zustellung warten. In diesem Fall muss der Client eine vollständige Synchronisierung mit dem Server durchführen.

Lesen Sie auch dieses Tutorial , um mit der Implementierung des CGM-Clients zu beginnen.

jogo
quelle
5

Dies beantwortet Entwickler, die das Xamarin-Framework verwenden (siehe /programming/40156342/sync-online-offline-data ).

Eine sehr einfache Möglichkeit, dies mit dem xamarin-Framework zu erreichen, ist die Verwendung der Offline-Datensynchronisierung von Azure, mit der Daten bei Bedarf vom Server übertragen und abgerufen werden können. Lesevorgänge werden lokal ausgeführt, und Schreibvorgänge werden bei Bedarf ausgeführt. Wenn die Netzwerkverbindung unterbrochen wird, werden die Schreibvorgänge in die Warteschlange gestellt, bis die Verbindung wiederhergestellt ist, und dann ausgeführt.

Die Implementierung ist ziemlich einfach:

1) Erstellen Sie eine mobile App im Azure-Portal (Sie können sie hier kostenlos testen: https://tryappservice.azure.com/ ).

2) Verbinden Sie Ihren Client mit der mobilen App. https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started/

3) den Code zum Einrichten Ihres lokalen Repositorys:

const string path = "localrepository.db";

//Create our azure mobile app client
this.MobileService = new MobileServiceClient("the api address as setup on Mobile app services in azure");

//setup our local sqlite store and initialize a table
var repository = new MobileServiceSQLiteStore(path);

// initialize a Foo table
store.DefineTable<Foo>();

// init repository synchronisation
await this.MobileService.SyncContext.InitializeAsync(repository);
var fooTable = this.MobileService.GetSyncTable<Foo>();

4) dann, um Ihre Daten zu pushen und zu ziehen, um sicherzustellen, dass wir die neuesten Änderungen haben:

await this.MobileService.SyncContext.PushAsync();
await this.saleItemsTable.PullAsync("allFoos", fooTable.CreateQuery());

https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-xamarin-forms-get-started-offline-data/

Ben Ishiyama-Levy
quelle
0

Ich schlage vor, Sie werfen auch einen Blick auf Symmetricds . Es ist eine SQLite-Replikationsbibliothek, die für Android-Systeme verfügbar ist. Sie können es verwenden, um Ihre Client- und Serverdatenbank zu synchronisieren. Ich empfehle außerdem, für jeden Client separate Datenbanken auf dem Server zu haben. Der Versuch, die Daten aller Benutzer in einer MySQL-Datenbank zu speichern, ist nicht immer die beste Idee. Insbesondere, wenn die Benutzerdaten schnell wachsen werden.

Hossein Shahdoost
quelle
0

Nennen wir es das CUDR-Synchronisierungsproblem (ich mag CRUD nicht - weil Erstellen / Aktualisieren / Löschen Schreibvorgänge sind und miteinander gepaart werden sollten)

Das Problem kann auch aus der Perspektive " Write-Off-Line-First" oder " Write-Online-First" betrachtet werden. Der Write-Offline-Ansatz hat ein Problem mit einem eindeutigen Identifizierungskonflikt und mehreren Netzwerkaufrufen für dieselbe Transaktion, was das Risiko (oder die Kosten) erhöht ...

Ich persönlich finde es einfacher, zuerst online zu schreiben (es wird also die einzige Quelle der Wahrheit sein - von wo aus alles andere synchronisiert wird). Der Write-Online-Ansatz erfordert, dass Benutzer nicht zuerst offline schreiben - sie schreiben offline, indem sie ein OK-Antwortformular für das Online-Schreiben erhalten.

Er kann zuerst offline lesen und sobald das Netzwerk verfügbar ist, die Daten online abrufen, die lokale Datenbank aktualisieren und dann die Benutzeroberfläche aktualisieren ....

Eine Möglichkeit, den eindeutigen Bezeichnerkonflikt zu vermeiden, besteht darin, eine Kombination aus eindeutiger Benutzer-ID + Tabellenname oder Tabellen-ID + Zeilen-ID (von SQLite generiert) zu verwenden ... und dann die synchronisierte boolesche Flag-Spalte damit zu verwenden Die Registrierung muss zuerst online erfolgen, um die eindeutige ID zu erhalten, auf der alle anderen IDs generiert werden. Hier tritt auch das Problem auf, wenn die Uhren nicht synchronisiert sind - was oben erwähnt wurde ...

Drachenfeuer
quelle
Außerdem hat der Offline-Schreibansatz ein Problem bei der Deinstallation der App. Alle nicht online hochgeladenen Daten werden gelöscht
DragonFire