Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Synchronisieren einer SQLite-Clientdatenbank mit einer MySQL-Serverdatenbank

Wie Sie erkennen, ist dies ein nicht triviales Problem. Ich habe letztes Jahr eine Bibliothek geschrieben, um dies für eine kommerzielle App zu erreichen, und es hat ungefähr 6 Monate gedauert, bis ich damit zufrieden war.

Abgesehen von dem Argument für die Verwendung von Port 80 und HTTP (TCP/IP), um Firewall- und Supportprobleme zu vermeiden, müssen Sie ein Protokoll entwerfen. Da mein Projekt sehr datenintensiv war, entschied ich mich für ein binäres Protokoll (anstelle des aufgeblähten XML), das alle Daten verarbeiten konnte. Ich wollte auch, dass es bidirektional ist, damit ich sowohl Daten EINFÜGEN als auch Anforderungen ausführen kann. Ich habe CGI/FastCGI auf dem Server verwendet.

Das von mir entworfene Binärprotokoll ist ziemlich einfach (immer besser) und zerlegt große Übertragungen in Stücke einer benutzerdefinierten Größe (ungefähr 600k scheint gut zu sein). Jeder Chunk hat einen Header, gefolgt von den Daten.

Obwohl dieses Protokoll zum Übertragen aller Arten von Daten verwendet werden kann, wird es normalerweise für Daten im Datenbankstil verwendet, wie Ihre Frage andeutet. Um dies zu berücksichtigen, entschied ich mich für einen Zeilen/Spalten-Ansatz für das Design. Die Daten werden zeilenweise gespeichert, d. h. jede Spalte wird für Zeile 1 gespeichert, dann alle Spalten für Zeile 2 ... Zeile n.

Das Format der Daten einer einzelnen Spalte ist:

' Col1Type          1Bytes - BYTE     ' Data Type (REMSQL_TEXT etc)                
' Col1Len           4Bytes - DWORD    ' Length in bytes the Column Data                            - up to 4.2GB
' Col1Data          nBytes - BYTE     ' String data  

(in C ist ein BYTE CHAR)

Das bedeutet, dass jede Spalte einen Datentypdeskriptor hat. Alle Datentypen können dargestellt werden mit:

REMSQL_NONE = 0    ' DataType undefined
REMSQL_QUAD = 1    ' 64-bit signed integer                
REMSQL_DBLE = 2    ' 64-bit IEEE floating point number
REMSQL_TEXT = 3    ' STRING - (CHAR) string of Ascii Bytes                                     
REMSQL_BLOB = 4    ' BLOB - (CHAR) string of Binary Bytes                                       
REMSQL_NULL = 5    ' NULL - Empty Column

Diese Datentypen stimmen mit den grundlegenden Datentypen von SQLite überein und sind numerisch äquivalent zur Aufzählung der grundlegenden Datentypen von SQL3.

Wenn in diesem Design ein Feld leer ist (NULL), haben Sie nur 5 Bytes zum Speichern benötigt. Wenn ein Feld beispielsweise 200 Bytes Text enthält, werden nur 205 Bytes zum Speichern benötigt. Der größere Vorteil liegt im Analysieren der Daten, da Spalten übersprungen werden können, ohne alle 200 Bytes zu lesen, um ein abschließendes Zeichen zu finden.

Der Chunk-Header sollte Dinge wie die Anzahl der Zeilen, die Anzahl der Spalten, die Gesamtzahl der Bytes usw. usw. enthalten. Wenn Sie DWORDs (vorzeichenlose 64-Bit-Ganzzahlen) verwenden, beträgt die theoretische Grenze für einen Chunk 4,2 GB, was selbst für die Übertragung im lokalen Netzwerk ausreichen sollte.

Die Implementierung erfordert das Schreiben von SQLite/MYSQL-Wrappern für diese Funktionalität. Ich verwende ausschließlich das BINARY-Protokoll, was etwas Zeit in Anspruch nimmt, aber Sie benötigen im Wesentlichen die folgenden Funktionen:Client-Seite:SendRequest() - Sendet Anfrage, wartet auf Antwort

Serverseitig:ProcessRequest() - Empfängt Anfrage, verarbeitet sie und gibt Antwort zurück

In meinem Fall kann die Antwort !00 MB Daten oder mehr betragen. Ich rufe den gesamten Datensatz von MySQL ab und speichere ihn auf der Festplatte des Servers. Dann gebe ich einen leeren Chunk zurück, der die Datensatzmetriken enthält. Der Client fordert dann den Datensatz in Blöcken von 600 KB an, einen nach dem anderen. Wenn die Verbindung unterbrochen wird, macht es einfach dort weiter, wo es aufgehört hat.

Schließlich bestand der Datensatz hauptsächlich aus Text (Namen, Adressen usw.), der so reif für die Komprimierung war. Sicherheit war in diesem Fall ein sehr großes Thema, daher war Verschlüsselung unerlässlich. Dies wird etwas komplizierter zu implementieren, aber im Grunde komprimieren Sie den gesamten Chunk, füllen ihn auf eine Länge auf, die ein Vielfaches der Blockchiffren BLOCKSIZE ist, und verschlüsseln ihn.

Dabei schreibe ich eine sehr schnelle String-Builder-Klasse, eine Implementierung der AES-Verschlüsselung in ASM und eine komplette FastCGI-Bibliothek (www.coastrd.com)

Also wie gesagt, nicht trivial. Ich werde diese Bibliothek bald zur Verfügung stellen. Wenn Sie es ausprobieren möchten, senden Sie mir eine E-Mail.

Sobald Sie die Kommunikation geschrieben haben, können Sie mit dem Entwurf der Synchronisation beginnen. Ich würde entweder einen Hash für jeden Datensatz oder ein einfaches boolesches Flag verwenden. Wenn sich auf dem Server etwas ändert, senden Sie einfach den gesamten Datensatz und überschreiben Sie ihn auf der Client-Seite (vorausgesetzt, Sie versuchen, die Clients synchron zu halten ...)

Wenn Sie Ihre eigenen schreiben, posten Sie bitte hier Ihre Erfahrungen!

PS. Erwägen Sie, den Titel zu ändern, damit er suchfreundlicher ist. Vielleicht so etwas wie:

"Synchronisieren einer SQLite-Client-Datenbank mit einer MySQL-Server-Datenbank"