Ich habe das Gefühl, dass es da draußen Client-Server-Synchronisationsmuster geben muss. Aber ich habe es total versäumt, einen zu googeln.
Die Situation ist recht einfach: Der Server ist der zentrale Knoten, über den mehrere Clients eine Verbindung herstellen und dieselben Daten bearbeiten. Daten können in Atome aufgeteilt werden. Im Falle eines Konflikts hat alles, was sich auf dem Server befindet, Priorität (um zu vermeiden, dass Benutzer zur Konfliktlösung gebracht werden). Eine teilweise Synchronisation wird aufgrund möglicherweise großer Datenmengen bevorzugt.
Gibt es Muster / bewährte Verfahren für eine solche Situation oder wenn Sie keine kennen - wie würden Sie vorgehen?
Nachfolgend denke ich, wie ich es jetzt lösen soll: Parallel zu den Daten wird ein Änderungsjournal geführt, in dem alle Transaktionen mit einem Zeitstempel versehen sind. Wenn der Client eine Verbindung herstellt, erhält er alle Änderungen seit der letzten Prüfung in konsolidierter Form (der Server durchläuft Listen und entfernt Ergänzungen, auf die Löschungen folgen, führt Aktualisierungen für jedes Atom zusammen usw.). Et voila, wir sind auf dem neuesten Stand.
Alternativ können Sie das Änderungsdatum für jeden Datensatz beibehalten und statt Datenlöschungen einfach als gelöscht markieren.
Irgendwelche Gedanken?
Antworten:
Sie sollten sich ansehen, wie verteiltes Änderungsmanagement funktioniert. Schauen Sie sich SVN, CVS und andere Repositorys an, die die Arbeit von Deltas verwalten.
Sie haben mehrere Anwendungsfälle.
Änderungen synchronisieren. Ihr Änderungsprotokoll- (oder Delta-Verlaufs-) Ansatz sieht dafür gut aus. Clients senden ihre Deltas an den Server. Der Server konsolidiert und verteilt die Deltas an die Clients. Dies ist der typische Fall. Datenbanken nennen dies "Transaktionsreplikation".
Der Client hat die Synchronisation verloren. Entweder durch ein Backup / Restore oder wegen eines Fehlers. In diesem Fall muss der Client den aktuellen Status vom Server abrufen, ohne die Deltas durchlaufen zu müssen. Dies ist eine Kopie vom Meister bis ins Detail, Deltas und Leistung sind verdammt. Es ist eine einmalige Sache; der Client ist kaputt; Versuchen Sie nicht, dies zu optimieren, sondern implementieren Sie einfach eine zuverlässige Kopie.
Der Kunde ist misstrauisch. In diesem Fall müssen Sie den Client mit dem Server vergleichen, um festzustellen, ob der Client auf dem neuesten Stand ist und Deltas benötigt.
Sie sollten dem Entwurfsmuster der Datenbank (und des SVN) folgen, bei dem jede Änderung fortlaufend nummeriert wird. Auf diese Weise kann ein Client eine triviale Anfrage stellen ("Welche Revision sollte ich haben?"), Bevor er versucht, eine Synchronisierung durchzuführen. Und selbst dann ist die Abfrage ("Alle Deltas seit 2149") für Client und Server sehr einfach zu verarbeiten.
quelle
Als Teil des Teams habe ich eine ganze Reihe von Projekten durchgeführt, bei denen es um die Synchronisierung von Daten ging. Daher sollte ich kompetent sein, diese Frage zu beantworten.
Die Datensynchronisierung ist ein ziemlich weit gefasstes Konzept und es gibt viel zu viel zu diskutieren. Es deckt eine Reihe verschiedener Ansätze mit ihren Vor- und Nachteilen ab. Hier ist eine der möglichen Klassifizierungen basierend auf zwei Perspektiven: Synchron / Asynchron, Client / Server / Peer-to-Peer. Die Implementierung der Synchronisierung hängt stark von diesen Faktoren, der Komplexität des Datenmodells, der übertragenen und gespeicherten Datenmenge und anderen Anforderungen ab. In jedem Einzelfall sollte die Wahl zugunsten der einfachsten Implementierung getroffen werden, die den App-Anforderungen entspricht.
Basierend auf einer Überprüfung bestehender Standardlösungen können wir mehrere Hauptklassen der Synchronisierung abgrenzen, die sich in der Granularität der zu synchronisierenden Objekte unterscheiden:
Daher haben wir unser Wissen in diesen Artikel eingebracht, der meiner Meinung nach für alle, die sich für das Thema interessieren, sehr nützlich sein könnte => Datensynchronisierung in zentralen datenbasierten iOS-Apps ( http://blog.denivip.ru/index.php/2014/04) / Datensynchronisierung in Kerndaten-basierten iOS-Apps /? lang = de )
quelle
Was Sie wirklich brauchen, ist Operational Transform (OT). Dies kann in vielen Fällen sogar zu Konflikten führen.
Dies ist immer noch ein aktives Forschungsgebiet, aber es gibt Implementierungen verschiedener OT-Algorithmen. Ich bin seit einigen Jahren an solchen Forschungen beteiligt. Lassen Sie mich wissen, ob diese Route Sie interessiert, und ich werde Sie gerne auf relevante Ressourcen hinweisen.
quelle
Die Frage ist nicht ganz klar, aber ich würde mich mit optimistischem Sperren befassen, wenn ich Sie wäre. Es kann mit einer Sequenznummer implementiert werden, die der Server für jeden Datensatz zurückgibt. Wenn ein Client versucht, den Datensatz zurückzuspeichern, enthält er die vom Server empfangene Sequenznummer. Wenn die Sequenznummer mit dem übereinstimmt, was sich zum Zeitpunkt des Empfangs der Aktualisierung in der Datenbank befindet, ist die Aktualisierung zulässig und die Sequenznummer wird erhöht. Wenn die Sequenznummern nicht übereinstimmen, ist die Aktualisierung nicht zulässig.
quelle
Ich habe vor ungefähr 8 Jahren ein solches System für eine App erstellt und kann einige Möglichkeiten erläutern, wie es sich mit zunehmender App-Nutzung entwickelt hat.
Ich begann damit, jede Änderung (Einfügen, Aktualisieren oder Löschen) von einem Gerät in einer "Verlauf" -Tabelle zu protokollieren. Wenn beispielsweise jemand seine Telefonnummer in der Tabelle "Kontakt" ändert, bearbeitet das System das Feld contact.phone und fügt einen Verlaufsdatensatz mit action = update, field = phone, record = [Kontakt-ID] hinzu. value = [neue Telefonnummer]. Bei jeder Synchronisierung eines Geräts werden die Verlaufselemente seit der letzten Synchronisierung heruntergeladen und auf die lokale Datenbank angewendet. Dies klingt wie das oben beschriebene Muster "Transaktionsreplikation".
Ein Problem besteht darin, IDs eindeutig zu halten, wenn Elemente auf verschiedenen Geräten erstellt werden können. Ich wusste nichts über UUIDs, als ich dies startete, also habe ich automatisch inkrementierende IDs verwendet und einen verschlungenen Code geschrieben, der auf dem zentralen Server ausgeführt wird, um neue IDs zu überprüfen, die von Geräten hochgeladen wurden, und sie bei einem Konflikt in eine eindeutige ID zu ändern Weisen Sie das Quellgerät an, die ID in seiner lokalen Datenbank zu ändern. Nur die IDs neuer Datensätze zu ändern war nicht so schlecht, aber wenn ich zum Beispiel ein neues Element in der Kontakttabelle erstelle, dann erstelle ich ein neues verwandtes Element in der Ereignistabelle, jetzt habe ich Fremdschlüssel, die ich auch brauche überprüfen und aktualisieren.
Schließlich erfuhr ich, dass UUIDs dies vermeiden konnten, aber bis dahin wurde meine Datenbank ziemlich groß und ich befürchtete, dass eine vollständige UUID-Implementierung ein Leistungsproblem verursachen würde. Anstatt vollständige UUIDs zu verwenden, habe ich zufällig generierte alphanumerische Schlüssel mit 8 Zeichen als IDs verwendet und meinen vorhandenen Code zur Behandlung von Konflikten beibehalten. Irgendwo zwischen meinen aktuellen 8-Zeichen-Schlüsseln und den 36 Zeichen einer UUID muss es einen Sweet Spot geben, der Konflikte ohne unnötiges Aufblähen beseitigt. Da ich jedoch bereits über den Konfliktlösungscode verfüge, war es keine Priorität, damit zu experimentieren .
Das nächste Problem war, dass die Verlaufstabelle etwa zehnmal größer war als der gesamte Rest der Datenbank. Dies verteuert die Lagerung und jede Wartung der Verlaufstabelle kann schmerzhaft sein. Wenn Sie die gesamte Tabelle beibehalten, können Benutzer alle vorherigen Änderungen rückgängig machen, aber das fühlte sich wie ein Overkill an. Daher habe ich dem Synchronisierungsprozess eine Routine hinzugefügt. Wenn das Verlaufselement, das ein Gerät zuletzt heruntergeladen hat, nicht mehr in der Verlaufstabelle vorhanden ist, gibt der Server ihm nicht die letzten Verlaufselemente, sondern eine Datei mit allen Daten für dieser Account. Dann habe ich einen Cronjob hinzugefügt, um Verlaufselemente zu löschen, die älter als 90 Tage sind. Dies bedeutet, dass Benutzer Änderungen, die weniger als 90 Tage alt sind, weiterhin rückgängig machen können. Wenn sie mindestens alle 90 Tage synchronisiert werden, werden die Aktualisierungen wie zuvor inkrementell durchgeführt. Aber wenn sie länger als 90 Tage warten,
Durch diese Änderung wurde die Größe der Verlaufstabelle um fast 90% reduziert. Durch die Verwaltung der Verlaufstabelle wird die Datenbank jetzt nur noch doppelt so groß anstatt zehnmal so groß. Ein weiterer Vorteil dieses Systems besteht darin, dass die Synchronisierung bei Bedarf immer noch ohne die Verlaufstabelle funktionieren kann - beispielsweise, wenn ich Wartungsarbeiten durchführen musste, die es vorübergehend offline schalteten. Oder ich könnte verschiedene Rollback-Zeiträume für Konten zu unterschiedlichen Preisen anbieten. Wenn mehr als 90 Tage lang Änderungen zum Herunterladen erforderlich sind, ist die gesamte Datei normalerweise effizienter als das inkrementelle Format.
Wenn ich heute von vorne anfangen würde, würde ich die ID-Konfliktprüfung überspringen und nur eine Schlüssellänge anstreben, die ausreicht, um Konflikte zu beseitigen, mit einer Art Fehlerprüfung für alle Fälle. Die Verlaufstabelle und die Kombination aus inkrementellen Downloads für aktuelle Updates oder einem vollständigen Download bei Bedarf haben jedoch gut funktioniert.
quelle
Für die Delta-Synchronisierung (Änderungssynchronisierung) können Sie das Pubsub-Muster verwenden, um Änderungen auf allen abonnierten Clients zu veröffentlichen. Dienste wie Pusher können dies tun.
Bei der Datenbankspiegelung verwenden einige Webframeworks eine lokale Minidatenbank, um die serverseitige Datenbank mit der lokalen Datenbank in der Browserdatenbank zu synchronisieren. Eine teilweise Synchronisierung wird unterstützt. Überprüfen Sie das Messgerät .
quelle