Hallo zusammen, Ich hab da mal ne eigentlich triviale Frage, aber ich stell sie jetzt mal, da ich nicht vom Fach bin. Folgendes: Es geht darum, eine Datenbank mit SQL/SQlite/MariaDB (also genauer gesagt nur eine Tabelle der Datenbank) einer App auf einem Smartphone mit einem Server zu Synchronisieren. Also das die Daten auch Online von überall her einsehbar und veränderbar sind, und entsprechend auch wieder auf der App Synchronisiert werden. Nun geht es darum WIE ich das am schlausten/effizientischsten mache? Bis jetzt habe ich dafür json genutzt. Aber wie übertrage ich 10'000 Einträge und mehr auf einmal, wenn sie geändert wurden? Klar würde json gehen. Aber wie würde man sowas das im Professionellen Bereich realisieren? Wie gesagt, nicht vom Fach. Darum wäre ich um ein paar Inputs froh : ) lg lukas88
Ich würde den einfachsten Weg gehen und nur die DB am Server nutzen. Entweder via TLS-gesicherter Verbindung dorthin eine SQL-Verbindung aufbauen, oder besser, am Server eine REST API entwickeln über die alles läuft und die Abfragen von der DB-Ebene abstrahiert. Was Du beschreibst (DB-Änderungen am Server mit der DB in der App synchronisieren und umgekehrt) klingt nach einem Master/Master Setup. Die können aber recht tricky sein und bei der Entwicklung muß das mit berücksichtigt werden (Transaktionen, Row- vs Statement-based Replication, Locking). Master/Slave ist simpler, aber dann kann man halt nur in der einen App auf dem einen Smartphone oder am Server Änderungen machen, denn der Slave ist readonly. Und den Master auf dem Handy laufen lassen ist Blödsinn. Daher, mach eine API.
ms schrieb: > Ich würde den einfachsten Weg gehen und nur die DB am Server nutzen. Geht leider nicht. Mein Hoster verbietet direkte DB anfragen von aussen, nur von intern via php&Co. Ist wahrscheinlich eine Sicherheitsvorkehrung. Ansonsten wäre eine API auch meine Wahl gewesen. Aufwendig, aber wahrscheinlich das Flexibelste und Sauberste. vielen Dank
"Klassisch" kann man natürlich die ganze DB dumpen und kopieren. Do the math, wie viele Rohdaten hat ein Record? Wie viele Records? Wie viel ist das gezippt? Bei 10.000 Records könnte das noch gehen. Wenn du eines oder mehrere Ziele up to date halten willst brauchst du serverseitig eine Art Versionierung, so dass du nur die Änderungen übertragen musst, das kann man dann auch mit Zeitstempeln machen. Die von ms angesprochene Api muss dann z.B. eine "getUpdates"-Funktion haben, die ab einem gegebenen Wiederaufsetzpunkt eine begrenzte Anzahl von Änderungen liefert und den neuen Wiederaufsetzpunkt, bis zu dem diese Daten gehen. Wenn der Client die Daten verarbeitet hat kann er sofort oder später nochmal fragen.
Lukas G. schrieb: > Geht leider nicht. Mein Hoster verbietet direkte DB anfragen von aussen, > nur von intern via php&Co. Ist wahrscheinlich eine > Sicherheitsvorkehrung. Ansonsten wäre eine API auch meine Wahl gewesen. > Aufwendig, aber wahrscheinlich das Flexibelste und Sauberste. Das MySQL nicht von außen einfach so erreichbar ist, ist schon gut so. Sollte man auch nicht aufmachen. Aber warum sollte das den Aufbau einer API unmöglich machen? Die läuft ja am Server selbst, und dort ist die DB dann als localhost erreichbar. Die Anfragen selbst laufen dann via HTTPS, und das wird dein Hoster ja wohl erlauben. Tilo R. schrieb: > Die von ms angesprochene Api muss dann z.B. eine "getUpdates"-Funktion > haben, Und pushUpdates. Das Ganze erfordert dann (wenn man offline arbeiten können will) auch den Aufbau einer History. Bei einem Master/Slave wäre das das Binlog, aber mit Triggern kann man sich auch eine History Tabelle aufbauen und die Änderungen von da in die DB am Server übertragen. Wird halt umständlicher.
Tilo R. schrieb: > "Klassisch" kann man natürlich die ganze DB dumpen und kopieren. Als Nachtrag noch: wenn das ganze Multiuserfähig werden soll, kann man sowas knicken. Nichts ist lustiger, als wenn User A einen Datensatz zum Editieren offen hat, und währenddessen die DB mit neuen Daten befüllt wird. Wenn er dann speichert, ändert er Daten die eventuell anders sind, oder noch besser, komplett andere Daten wenn sich die ID ändert (was sie nicht sollte, aber man weiß ja nie). Da braucht es das noch einen Lockmechanismus, und spätestens dann ist eigenlich Schluß mit DB austauschen, oder Dump einspielen.
Lukas G. schrieb: > Aber wie würde man sowas das im Professionellen Bereich > realisieren? Schwierig. Die einfachste Lösung wäre, den beteiligten Tabellen jeweils Spalten mit "created" und "last_changed" zu spendieren und dann... genau. Dummerweise kannst Du bei nicht verbundenen Datenbanken keine konsistenten Primärschlüssel vergeben und mußt Dir obendrein auch noch eine Auflösung von Konflikten überlegen. Denn irgendwie mußt Du den Fall behandeln, daß der Datensatz 123 in den Instanzen unabhängig voneinander geändert wurde. Leider sagst Du nicht sonderlich viel über Deinen Anwendungsfall, deshalb würde ich vermutlich zuerst überlegen, ein Art von REST-API über HTTPS zu verwenden und JSON als Datenformat verwenden. Das ist vermutlich nicht zu schwierig, kann GZIP zur Kompression der Daten, und zudem TLS-Zertifikate für Authentifizierung und Autorisierung verwenden.
ms schrieb: > Als Nachtrag noch: wenn das ganze Multiuserfähig werden soll, kann man > sowas knicken. Nichts ist lustiger, als wenn User A einen Datensatz zum > Editieren offen hat, und währenddessen die DB mit neuen Daten befüllt > wird. Wenn er dann speichert, ändert er Daten die eventuell anders sind, > oder noch besser, komplett andere Daten wenn sich die ID ändert (was sie > nicht sollte, aber man weiß ja nie). > > Da braucht es das noch einen Lockmechanismus, und spätestens dann ist > eigenlich Schluß mit DB austauschen, oder Dump einspielen. Das kann man auch ohne Locking lösen, und wird im Distributed Computing auch (zwangsläufig) ohne Lock gelöst, etwa indem man jedem Datensatz eine Versionsnummer verpaßt und die bei jedem Write hochzählt. Gleichzeitig muß der Client die Versionsnummer beim Schreiben überprüfen, und wenn der Datensatz inzwischen geändert wurde und die Versionsnummer also größer ist als jene, die der Client editiert hat, muß der Client den Konflikt lösen. Das ist aber ziemlich aufwändig -- und erfordert vor allem, daß absolut alle Clients sich an dieses Protokoll halten.
Wahrscheinlich hilft es dir bei einer bestehenden Datenbank nicht, aber das hier ist genau dafür gemacht: https://couchdb.apache.org/
Die ganzen Locking-Probleme und Lösungsmöglichkeiten sind natürlich richtig. Aber wenn die Applikation im ersten Wurf nicht gleich das neue Facebook werden soll, geht es vielleicht deutlich einfacher. Müssen denn überhaupt gleichzeitig mehrere Nutzer schreiben können? Falls nicht (oder falls du der einzige schreibende Nutzer bist) --> kein Problem. Falls doch: müssen die die selben Daten bearbeiten? Falls z.B. jeder in einem eigenen Bereich arbeitet oder Überschneidungen hinreichend unwahrscheinlich sind --> kein Problem Falls doch: ist die Sache performancekritisch? Falls du z.B. weniger als 1000 User hast ist es denkbar, schreibende Änderungen serverseitig nacheinander abzuarbeiten und dabei eine ändere-von-auf-Logik zu verwenden. Falls 2 schreibende Anfragen gleichzeitig kommen muss einer warten, und wenn der von-Wert nicht mehr stimmt bekommt er eine Fehlermeldung. (Die von ein_typ vorgeschlagene Versionierung funktioniert ähnlich) Wichtiger als das Locking Problem ist sicher zu stellen, dass die API kein SQL-Injection-Problem hat.
Tilo R. schrieb: > Die ganzen Locking-Probleme und Lösungsmöglichkeiten sind natürlich > richtig. > Aber wenn die Applikation im ersten Wurf nicht gleich das neue Facebook > werden soll, geht es vielleicht deutlich einfacher. > > Müssen denn überhaupt gleichzeitig mehrere Nutzer schreiben können? > Falls nicht (oder falls du der einzige schreibende Nutzer bist) --> kein > Problem. > > Falls doch: müssen die die selben Daten bearbeiten? Falls z.B. jeder in > einem eigenen Bereich arbeitet oder Überschneidungen hinreichend > unwahrscheinlich sind --> kein Problem Im Laufe der Jahre habe ich mich schon mehrmals zu solchen "kein Problem"-Ansätzen breitschlagen lassen. Ich bin damit jedes Mal voll auf meine Nase gefallen hatte am Ende meistens die begrenzte Freude, meine Daten manuell wieder glattziehen zu müssen. Deswegen lasse ich mich sowas nur noch dann ein, wenn mein Vorgesetzter oder Kunde schriftlich erklärt, daß ich über die Risiken aufgeklärt habe und im Fehlerfall nicht mit der Bereinigung beschädigter Datenbestände beauftragt werde. Sowas macht nämlich überhaupt gar keinen Spaß, wenn es überhaupt möglich ist. Denn wenn die Daten groß genug sind und die Inkonsistenzen erst nach längerer Zeit auffallen, dann können die Daten schon so kaputt sein, daß man sie nicht mehr reparieren und in einen korrekten, konsistenten Zustand überführen kann. Wie gesagt, leider sagt der TO nicht sonderlich viel über seinen genauen Anwendungsfall, also: was das für Daten sind, wie viele Nutzer es geben soll, ob ein mobiles Editieren nötig ist, woher die Daten kommen, und so weiter. Und ich fürchte, wirklich konstruktiv können wir dazu erst dann ausführen, wenn der TO seinen Anwendungsfall genauer erklärt hat.
ms schrieb: > Das MySQL nicht von außen einfach so erreichbar ist, ist schon gut so. > Sollte man auch nicht aufmachen. Aber warum sollte das den Aufbau einer > API unmöglich machen? Macht es auch nicht unmöglich. Ist da dann auch Serverintern. Es geht einfach nicht direkt über die Datenbank, weil sie eben von aussen nicht erreichbar ist. Bei meinem letzten Hoster konnte ich mich noch direkt in die Datenbank Einloggen und Einträge löschen,ändern,hinzufügen, ect. Aber du hast schon recht. MySQL sollte von aussen nicht erreichbar sein,von dem her. Darum strebe ich auch eine API an. lg lukas88
Ein T. schrieb: > Wie gesagt, leider sagt der TO nicht sonderlich viel über seinen genauen > Anwendungsfall, also: was das für Daten sind, wie viele Nutzer es geben > soll, ob ein mobiles Editieren nötig ist, woher die Daten kommen, und so > weiter. Und ich fürchte, wirklich konstruktiv können wir dazu erst dann > ausführen, wenn der TO seinen Anwendungsfall genauer erklärt hat. Hast recht, darum: -Es geht um eine Private App, soll also nicht in den Play Store, App Store,ect -Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz, Kategorie ect also keine Bilder oder sogar Videos. -Benutzer sind genau ich vorgesehen. Aber mit der Option, die Nutzeranzahl auf maximal 5 zu anzupassen. -Einträge rechne ich jetzt mal mit minimal 3 pro Tag*365 =1095. Das ganze wird aber voraussichtlich die nächsten paar Jahre laufen, und sollte auch stetig erweitert werden. Darum die geschätzten 10 000 Einträge. -Mobiles editieren möchte ich auch implementieren, sonst mach ja das Synchronisieren fast keinen Sinn.
Lukas G. schrieb: > Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz, > Kategorie ect also keine Bilder oder sogar Videos. Schau dir an, wie eine Versionsverwaltungssoftware, z.B. git, das macht. Musst deswegen ja kein git in deine App einbetten (obwohl das auch ginge), aber das Prinzip kannst du dir abschauen. Da kann jeder Nutzer offline an seinem Versionsstand rumwerkeln, und trotzdem kriegst du das nachher wieder zusammengefasst in einen gemeinsamen Datenbestand. Konflikte, wenn zwei Leute dieselbe Zeile gleichzeitig bearbeitet haben, kannst du ganz pragmatisch lösen: Einfach beide Versionen hintereinander schreiben, mit ">>>> Änderung von User A" ... ">>>> Änderung von User B" ... "<<<<" Markern außenherum. Je nach Anwendung dann so stehen lassen, oder irgendjemand muss sich das ansehen und entscheiden, was stehen bleiben soll.
Lukas G. schrieb: > -Bei den Daten geht es Hauptsächlich um Text. Also Datum, Uhrzeit,Notiz, > Kategorie ect also keine Bilder oder sogar Videos. > > -Benutzer sind genau ich vorgesehen. Aber mit der Option, die > Nutzeranzahl auf maximal 5 zu anzupassen. Also Multiuser. Da würde ich die Idee mit der Synchronisierung vergessen, stattdessen fallen mir auf die Schnelle zwei Lösungen ein: - serverseitige Versionsnummern und / oder Zeitstempel in der Datenbank, mit denen parallele Zugriffe erkannt und Konflikte manuell gelöst werden. - ein temporäres, exklusives Write Lock in der Datenbank. Wenn der Client innerhalb der eingestellten Zeit schreibt, wird das Write Lock aufgehoben. Wenn nicht (Client wurde abgelenkt, hat die Internetverbindung verloren, oder ähnlich), wird es nach der eingestellten Zeit freigegeben. Das kann die clientseitige App mit entsprechenden Warnungen unterstützen. Die zweite Lösung erscheint mir deutlich eleganter, weil dabei keinerlei Konflikte auftreten können, wenn sie sauber implementiert ist. Sie erfüllt aber Deine Forderung nach Synchronisation nicht. Mir fällt gerade aber nur eine mögliche Lösung ein, wie eine saubere Synchronisation mit mehr als einem Client gelöst werden sollte, und die... nein. ;-)
Also couchdb sieht nicht übel aus. Leider wahrscheinlich für mich etwas zu Overkill. Ich merke aber,das es Komplexer ist als ich bis anhin dachte. Wahrscheinlich entscheide ich mich für einen Kompromiss. - Zugriff per API - "Halb" Synchron. Also Löschen,Hinzufügen,ändern immer aktiv mit der Datenbank auf dem Server Synchronisieren. Änderungen die nicht auf dem Mobile Device gemacht wurden, werden nur manuell aktiv durch den Benutzter ausgelöst, oder in Zeitlichen Intervallen werden Versionsnummern der Datenbank verglichen und gegeben falls Synchronisiert. -Write Lock bei gleichzeitigem Zugriff.Bei Write Lock Kollision bei mehreren Usern entweder Fehlermeldung beim Client oder solange warten, bis die Datenbank wieder "frei" (vielleicht mit "Warteliste") Besten dank für eure hilfreichen inputs lg lukas88
Kolja L. schrieb: > Wahrscheinlich hilft es dir bei einer bestehenden Datenbank nicht, aber > das hier ist genau dafür gemacht: https://couchdb.apache.org/ Bitte entschuldige, aber könntest Du vielleicht etwas dazu sagen, was CouchDB für diesen Anwendungsfall besonders qualifiziert und welche Features es anbietet, um das Concurrency-Problem zu lösen?
Ich arbeite zu 90% mit PHP (Symfony). Hier würde ich ein Feld in die Tabelle legen, das den last_change speichert. Und dann über eine JSON-API und mit Queued Message Handling das ganze asynchron und sauber im Hintergrund synchronisieren... Auf dieser Weise verschicken Programme von mir Einzelemails von 7-stelligen Adresslisten ohne Sorgen
Ich würde jedem Eintrag eine Verisonsnummer geben, die bei jeder Änderung per trigger hochgezählt oder geändert wird. Dann würde ich einen Endpunkt machen, der alle Verionsnummern entgegennimmt, schaut, ob die in der DB anders (oder grösser) sind, und wenn ja, den Eintrag zurück gibt. Bei Änderungen des Nutzers muss die Verisonsnummer natürlich auch zurückgegeben werden. Man kann die auch gruppieren. Hat man z.B. den selben counter für alle Tabellen, kann man einfach eine Versionsnummer mitgeben, und dann einfach überall schauen, wenn (dbversion-clientversion > 0), dann wurde es geändert. Das schreiben skalliert aber nicht gut, sobald man mehrere DBs an mehreren Standorten hat, kann man das nicht mehr gut synchronisieren, das ist kein kleines Problem. Gibt zwar sicher möglichkeiten, da gegenzusteuern. (Das lesen dürfte dafür aber sehr effizient sein.) Bei Mehreren Versionsnummern und einfachem vergleich ob alt != neu, ist das einfacher, da kann man einfach eine UUID generieren, weil man ja dort nicht schaut, ist es neuer, und die IDs unabhängig voneinander sind. Aber dann muss man die sich halt beim client alle merken, und das kann mit seinen eigenen Problemchen kommen. Was da am einfachsten ist, dürfte stark von der Infrastruktur, und wer alles welche ressourcen bearbeiten kann abhängen. Auch kombinationen davon können sinn machen. Eventuell kann man auch mit der momentanen Zeit und eventual consistency herumspielen. Da spielt dann auch noch eine Rolle, ob man konflikte bei änderungen erkennen will, oder nicht. Für die Datenübertragung selbst würde ich weiterhin einfach JSON nehmen. Der Browser wird es beim senden gzip komprimieren. Falls du eine Historie alter Einträge hast, könnte man auch einen diff zurückliefern. Es gibt da sogar diverse halbstandards, wie z.B. die HTTP PATCH methode, und anderes zeugs, aber meines wissens verwendet das keiner.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.