![]() |
Datenbank: Firebird/MySQL • Version: 2.1 • Zugriff über: -
Synchronisation zwischen Datenbanken - Ideen?
Guten Tach,
wir haben eine Anwendung im Umlauf, die Daten zwischen einer lokalen Firebird- und einer online MySQL-Datenbank austauscht (repliziert). Ist u.a. ein Kalender der hier so abgegelichen wird. Klappt auch soweit ganz gut. Es wird bei jeder Änderung ein Zeitstempel im jeweiligen Datensatz gesetzt und ein Sync-Prozess holt alle Änderungen (seit letztem Sync) ab und verschiebt diese an die Gegenstelle. Die Uhrzeiten zwischen lokal und Online DB werden dabei synchron gehalten. Jetzt gibt es seltenst (vielleicht 1 von 100 oder 1 von 1000 Terminen) den Fall dass ein Satz nicht synchronisiert wird. Der Termin fehlt dann halt online oder wird lokal nicht rausgelöscht, etc. Problem ist auch noch, dass mehrere Windows Rechner (Firebird) die gleiche MySQL Datenbank synchronisieren. Eine Änderung an Platz1 wird dann auf Platz2 verteilt usw. Wie handhabt ihr das mit der Synchronisation? Ich will jetzt keine Codebeispiele sondern eher Ideen etc. Viele Grüße, Jürgen Findeis |
AW: Synchronisation zwischen Datenbanken - Ideen?
Hi Delphi 2-Developer *fg*
und du bist dir sicher, dass der Termin nicht bei der Sync zwischen den einzelnen Firebird-Stationen flöten geht? Wie überwachst Du eigentlich das löschen? Bekommt der Datensatz ne Löschmarkierung oder wird der aus der Tabelle entfernt? Wenn Du den gleich raus löscht - wie stellst Du dann sicher, dass ein zweiter Client, bei dem der DS dann noch da ist, diesen nicht wieder aufnimmt? Grüße |
AW: Synchronisation zwischen Datenbanken - Ideen?
Zitat:
[OT]schön von Dir zu hören[/OT]. Ja, irgendwo muss der Satz verloren gehen. Ich überwache schon ob das INSERT etc. geklappt hat aber irgendeine Lücke muss es ja geben. Beim Löschen wird in einer speziellen Löschtabelle vermerkt dass Satz 0815 entfernt ist. Auch diese Info wird mit einem Zeitstempel versehen. The Same Procedure... Grüße, jf_stgt |
AW: Synchronisation zwischen Datenbanken - Ideen?
Ich kann mir nicht vorstellen, dass soetwas als Clientoperation in einem heterogenen Umfeld robust funktioniert. Allein schon verteilte Transaktionen innerhalb eines Systems können tückisch sein, abgesehen von der Synchronisationslogik.
Ich würde es bei heterogenen DB mit einem Application Server versuchen. |
AW: Synchronisation zwischen Datenbanken - Ideen?
Zitat:
Zitat:
Grüße |
AW: Synchronisation zwischen Datenbanken - Ideen?
[QUOTE=Lemmy;1103784]
Zitat:
|
AW: Synchronisation zwischen Datenbanken - Ideen?
[QUOTE=jobo;1103788]
Zitat:
|
AW: Synchronisation zwischen Datenbanken - Ideen?
So als Idee zur Synchronisieren...
Eine Tabelle mit Adressdaten (Namen, Strasse, PLZ, Ort, Land, Tel, EMail) wird unabhängig voneinander auf Notebooks im Aussendienst befüllt und soll auf die gemeinsame Tabelle auf'm Server synchronisiert werden. Alle Felder werden zu einem String verkettet und darüber ein Hashwert (MD4, MD5, SHA-40) errechnet:
Delphi-Quellcode:
Der Hashvalue wird zusätzlich zu den Adressdaten in einem eigenen, indizierten Feld gespeichert.
//
hashstring := Trim(name1)+'|'+Trim(name2)+'|'+Trim(strasse)+'|'+...'|'+Trim(EMail); hashvalue := HexString(CalcMD4(hashstring)); Der Hashvalue muss nicht zwingend der Primärschlüssel der Tabelle sein, sondern ist ggf. nur ein Surrogatschlüssel. Die einzelnen Felder werden vor dem Zusammenbau mit Trim() bearbeitet, damit Leerzeichen am Anfang oder Ende keine Rolle spielen. Es hängt vom Einzelfall ab, ob man zusätzlich auch noch UpperCase() anwenden sollte. Das Trennzeichen (hier '|') ist wichtig, damit die Position der Felder fixiert wird. Ausserdem wichtig: das Design der Tabelle muss von Anfang an passen; nachträgliches Hinzufügen von Felder ist schwierig, da eine Kollision der Hashwerte droht. Mit dem Hashvalue Feld gibt es ein eindeutiges Kriterium auf Grund dessen Synchronisiert werden kann. Löschen von Datensätzen: Die Datensätze werden nicht wirklich gelöscht, sondern nur mit dem Boolean-Feld "Deleted" markiert. Alle Datensätze bleiben daher quasi für immer erhalten. Diese können irgendwann mit
SQL-Code:
endgültig gelöscht werden.
DELETE FROM AdressTabelle WHERE Deleted<>0
Die Tabelle sieht dann also so aus:
Code:
PKey int
HashValue varchar(32) LastChange DateTime Created DateTime Deleted Bool (oder TinyInt oder Byte) Nutzdaten1 .... Nutzdaten2 .... |
AW: Synchronisation zwischen Datenbanken - Ideen?
Zitat:
Sollte letzteren der Fall sein, muß ich fragen: Wieso? Ist doch Quatsch! Ich denke aber, der erste Fall wird zutreffen sein, oder? Dann stell ich Dir die Frage: Wieso synchronisieren die einzelnen Win-Clients die MySQL-DB? Wenn jeder Client die MySQL-DB synchronisiert, muß das (vom Gefühl her schon) in die Hose gehen! Die Idee von SX2008 würde ich _so_ eher nicht verfolgen. Einen Hashwert über die Adresse zur Synchronisation von Terminen würde ich nicht verwenden. Das Eine hat (im Prinzip) nichts mit dem Anderen zu tun! Adressen können sich ändern! Und das tun sie heufiger, als man als Entwickler denkt. Selbst wenn man sagt, Okay, der Hashwert wird einmalig erzeugt, beim Anlegen beispielsweise. Die Praxis zeigt, das der EndNutzer gern im Eifer des Gefechtes (Telefonat, Kundengespräch usw.) nur einen Namen (z.B. "Frau Müller") als Adresse anlegt, evtl. einen Termin dazu, und erst später die komplette Adresse nachträgt. Den EndNutzer zur Eingabe der komplette Adresse zu "zwingen" ist eher kontra-produktiv und das Thema wird schnell auf wieder auf deinem Desktop liegen. Dein DB-Konzept zur Synchronisation hört sich recht gut an. Was ich allerdings ändern würde, wäre das nicht die Clients die Synchronisation der MySQL-Db vornehmen, sondern das das Ganze an einer zentralen Stelle passiert. Das könnte ein System-Dienst auf dem lokalen DB-Server übernehmen. Dann brauchen deine Termine einen eindeutigen ID. Deshalb verpasst du den Terminen neben dem Zeitstempel, der die letzte Änderung des Termins beschreibt (nennen wir ihn Änderungsstempel), einen weiteren Zeitstempel, der die Erstellung des Termins beschreibt, mit einer zusätzlichen Kennung in welcher DB der Termin erstellt wurde. Den nennen wir "Erstellstempel" oder einfach ID, dann das wäre dann einer. Wichtig: Für beide Zeitstempel nutzt du die Zeit des jeweiligen DB-Servers, nicht die des Clients! D.h. im SQL-Statement Now()!! Die zusätzlich DB-Kennung deswegen, weil die Zeiten der beiden DB's bzw. deren Server nicht zu 100% synchron sein werden. Den Surrogatschlüssel ala Hashwert, den SX2008 beschreibt, den hättest du dann mit dem Erstellstempel, sprich ID, unabhängig von der Adresse. Und der ist mit Sicherheit eindeutig und enthält sogar mehr Information! Kurz um: Lass die Synchronisation von einem zentralen Dienst auf dem lokalen DB-Server übernehmen und Dir dürfte kein Termin mehr durch die Lappen gehen. Dadurch, das nun jeder Termin einen eindeutigen ID (Erstellstempel) besitzt, entscheidet der Änderungsstempel, welcher Termin "Master" ist. |
AW: Synchronisation zwischen Datenbanken - Ideen?
Der Hashwert ist zwar ganz nett, aber dann muss jeder Client die gesamten Hashwerte vom Server laden, vergleichen und dann den passenden Datensatz nochmals vom Server holen.
Das mag bei wenigen Datensätzen und Clients funktionieren ... aber wenn die Anzahl Datensätze/Clients zunimmt kann man sich auch schön die Bandbreite damit verhageln. Hier meine Vorschläge zur Synchronisation mit minimalem Overhead: Zeitstempel Der Client fragt beim Server alle Datensätze ab, die neuer als der letzte Zeitstempel sind. Von diesen Daten wird der aktuellste Zeitstempel (vom Server vergeben) als letzter Zeitstempel beim Client gespeichert (nicht die Uhrzeit der letzten Abfrage!) Hauptproblem bei der Synchronisierung via Zeitstempel bleibt aber die Auflösung des Zeitstempels. Ein MySQL Server schafft ja (je nach Hardware) mehr als einen Datensatz pro Millisekunde zu speichern. xxx1 Client A schreibt Datensatz xxx2 Client B bekommt die Datensätze geliefert (höchster Zeitstempel xxx) xxx3 Client A schreibt Datensatz Bei der nächsten Abfrage bekommt Client B aber nicht den 2. Datensatz von A geliefert, denn dieser Datensatz hat ja auch den Zeitstempel xxx obwohl er nach der Abfrage von Client B geschrieben wurde. Somit müsste also die Abfrage nicht Zeitstempel > xxx lauten, sondern Zeitstempel >= xxx. Damit bekommt man aber wieder ein entsprechenden Overhead, den man evtl. vermeiden möchte/muss. Ein Ausweg aus diesem Zeitstempel-Dilemma geht dann nur über Update-Liste pro Client In einer Update-Tabelle werden alle Änderungen der Haupt-Tabelle auf dem Server (per Trigger) in diese Update-Tabelle eingetragen. Der Client fragt mit dieser Tabelle die Datensätze ab und löscht dann die verarbeiteten Sätze aus der Tabelle. Dadurch hat man dann auch das Weitergeben von Löschsätzen charmant gelöst, denn diese können sofort aus der Haupttabelle entfernt werden. Müssen mehrere Tabellen synchronisiert werden, dann eben den Tabellen-Namen mit in die Update-Tabelle, oder eine UUID als ID verwenden.
Code:
ClientID PK
RecordID PK DeleteFlag |
AW: Synchronisation zwischen Datenbanken - Ideen?
Noch eine Zeitstempel-Variation:
Die Daten werden nur mit einem Server synchronisiert und damit kann der eine "Zeit" festlegen: Die Anzahl der bereits erfolgten Synchronisationen. Angenommen der Server hat eine Zeit von 1337 und der Client wurde zuletzt bei 17 synchronisiert.
Nett wäre hier, wenn nicht ein anderer Client gleichzeitig auch versucht zu synchronisieren. |
AW: Synchronisation zwischen Datenbanken - Ideen?
Hmm ... das "Update-Liste pro Client"-Konzept ist auch eine Lösung.
Allerdings muß hier geklärt sein, welche DB die Master-DB stellt. Wenn ich den TO richtig verstanden habe, wird auf beiden DBs aktiv gearbeitet. Die Synchronisation muß also in beiden Richtungen stattfinden. Und da kommt man an einem Zeitstempel nicht vorbei. Allzumal die Synchronisation nicht zeitgleich passiert sondern mit Sicherheit in bestimmten zeitlichen Intervallen. Wie soll man verhindern, das z.B. Online ein Termin gelöscht und gleichzeitig (im gleichen Zeitintervall) der selbe Termin lokal nur verschoben wird. Oder auch umgekert. Das sind zwei unterschiedliche Vorgänge auf ein und die selbe Information (sprich Datensatz)! Selbst ein Mischen und Sortieren der Updatelisten beider DBs kann zu Datenverlust führen. Löschen von Datensätzen, die mit anderen DB's Synchronisiert werden sollen, halte ich daher immer für einen schlechte Idee. Eine Löschmarkierung ist hier der bessere Weg. Ich glaube grundsätzlich kann man sagen, dass das Synchronisieren von zwei (oder mehreren) DBs immer ein Problem darstellt und sollte immer von Anwendungsfall zu Anwendungsfall neu überdacht werden. Meines Erachtens ist es das wichtigste, das Termine (Datensätze) auf allen DBs einen eindeutigen ID besitzen, damit man sie jederzeit identifizieren kann. Zitat:
|
AW: Synchronisation zwischen Datenbanken - Ideen?
Die Update-Liste braucht man eigentlich nur auf dem Server, da dort die ausstehenden Änderungen pro Client gespeichert sind.
Gut so eine Tabelle kann der Client auch führen, dann ist das Handling der gelöschten Sätze einfacher. Einen Timestamp sollte man bei der Haupttabelle haben. Ein Löschen kann generell nicht verhindert werden, wenn das Löschen möglich sein muss. Wie wäre denn der Fall, wenn alle an einem Server arbeiten? Der Datensatz ist weg. Selbiges gilt für das Ändern von Datensätzen, da gewinnt die letzte Änderung. Um die herauszufinden benötigt man den Timestamp vom Client. Und da wartet schon die nächste Hürde: Am Client wird die Uhrzeit 3h vor gestellt und schon würden alle jetzt gemachten Änderungen gewinnen. Das ist aber auch schon fast ein anderes Thema. Hier ging es ja zunächst um die Sicherstellung, dass alle Objekt repliziert werden |
AW: Synchronisation zwischen Datenbanken - Ideen?
Für eindeutige IDs würde ich eine GUID nehmen. Ohne die geht es nicht.
Die Tabelle der durchgeführten Änderungen (eingefügt, gelöscht, verändert) als Basis für den Synchronisationsprozess ist schon richtig. Wenn Du dann noch Konflikte behandelst (Änderungen widersprechen sich), bist Du fertig. Ein Konflikt tritt z.B. dann auf, wenn der eine einen Datensatz löscht, ein Anderer den gleichen DS zwischenzeitlich jedoch verändert hat. Oder beide verändern ein und das selbe Feld eines DS. Du kannst hier entweder nach dem Prinzip "Last one wins" vorgehen, oder Du implementierst eine Konfliktbehandlung ("DS xy wurde von Schulze am BLABLA verändert, aber von Ihnen am BLABLUB gelöscht"). Da beim ersten Fall Datenänderungen unbemerkt verschwinden können, würde ich eine Konfliktbehandlung ("reconcile") implementieren. Das ist übrigens das sog. "briefcase model". Um solche Konflikte sicher erkennen zu können, könntest Du dir merken, "wann" (und vom wem) ein Feld zum letzten Mal geändert wurde. Liegt dieser Zeitpunkt NACH deinem letzten Abgleich (und du hast diesen DS/Feld) verändert, liegt ein Konflikt vor. Konfliktbehandlungen bekommst Du auch in den Griff, wenn Du dir eine Kopie der DB ("Original") nach erfolgter Synchronisation erstellst und vor der nächsten Synchronisation die Daten mit dieser DB-Version vergleichst: Hat sich ein zu ändernder Datensatz (Von 'A' nach 'B') zwischenzeitlich verändert, war die Änderung nicht exklusiv, es liegt dann also ein Konflikt vor. Du vergleichst also jeden DS VOR dem Abgleich mit dem Original. Damit erkennst Du zwar Konflikte, nicht jedoch, WER der Konfliktpartner ist. Ich würde den ersten Weg wählen: Man hat auch eine sehr mächtige Änderungshistorie, was bei Geschäftsdaten nicht unerheblich ist. Du kannst dann auch Fragen beantworten, wie: "Wer hat denn damals den Ansprechpartner von Fa. Halmackenreuther geändert". |
AW: Synchronisation zwischen Datenbanken - Ideen?
Oh, das sind ja viele Antworten. Danke!
Ich werde versuchen auf die wichtigsten Punkte einzugehen... Zitat:
Zitat:
Die Clients haben einen Dienst, der alle 30 Sekunden die Datenbanken automatisch durchkämmt. Also nicht vom Benutzer angestossen. Zuerst die eine, dann die andere Richtung. Zitat:
Ein update eines Satzes müsste natürlich auch ein Update des MD5 nach sich ziehen. Zitat:
Zitat:
Zitat:
Zitat:
Brauche ich jetzt noch die zusätzliche DB Kennung und wie meinst Du das genau mit dem Now(). Wenn ich lokal ein Now() mache habe ich ja die lokale Zeit. Du meinst bei jedem Insert die MySQL Zeit einzustempeln (Internertzugang weg - Perfomance?) ??? Sorry aber ich habs net ganz verstanden. Zitat:
Zitat:
Zitat:
Die Idee mit dem Erkennen der letzten Änderungen für Supportzwecke ist super! WEITERE ANMERKUNGEN: Eine Update Liste je Client wie von manchen gefordert hatten wir mal bei einer alten DB Technik. Das war super unperfomant - könnte bei FB jetzt besser gehen. Die Frage ist, ob man beides umsetzten sollte (Zeitstempel und Update-Liste). So könnte man Änderungen vielleicht sicherer erkennen. Sobald ein Satz entweder in der Update-Liste ODER über den Zeitstempel als geändert gilt ist er wirklich geändert. Mal überdenken... Was ich mir noch vorstellen könnte, dass vielleicht der Satz (Termin) gelöscht wird und(!) auf der anderen Seite verändert??!! Möglicherweise wird diese Kollission nicht erkannt? Ein Umbau auf ein Flag "IsDeleted" bei jedem Satz statt dem "echten" Löschen scheint mir auf alle Fälle sinnvoll. Aber dies ist natürlich auch nicht sofort erledigt bei ca. 50 Tabellen. Gruß Jürgen |
AW: Synchronisation zwischen Datenbanken - Ideen?
Zitat:
Stichwort "zeitweilig ohne Internet" Das meinte ich eigentlich mit robust. Wie arbeitest Du im Client mit Verbingungstrennung / -Abbruch? Z.B. nachdem Du bereits einige Daten auf mySQL aktualisiert hast. Da muss es doch zu Inkonsistenzen kommen, zwischen den DB hast Du doch keine Transaktionssicherheit. |
AW: Synchronisation zwischen Datenbanken - Ideen?
Mehrrechner-Datenbanksysteme
Grundlagen der verteilten und parallelen Datenbankverarbeitung ![]() |
AW: Synchronisation zwischen Datenbanken - Ideen?
Zitat:
Zitat:
Auf den Clients kommt eine Meldung sobald der "Haupt-Client" nicht mehr am Netz hängt und keine Änderungen gemacht werden sollen. Dies kommt ja nicht sooo häufig vor. Hauptsache auf dem Hauptrechner kann weiter gearbeitet werden. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:27 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz