sql >> Base de Datos >  >> RDS >> Mysql

Sincronización de una base de datos de cliente SQLite con una base de datos de servidor MySQL

Bueno, te das cuenta de que este no es un problema trivial. Escribí una biblioteca para lograr esto para una aplicación comercial el año pasado y tardé unos 6 meses en llegar a donde estaba satisfecho con ella.

Dejando de lado el argumento a favor del uso del puerto 80 y HTTP (TCP/IP) para evitar problemas de firewall y soporte, debe diseñar un protocolo. Dado que mi proyecto era muy intensivo en datos, opté por un protocolo binario (en lugar del xml inflado) que podía manejar cualquier dato. También quería que fuera bidireccional para poder INSERTAR datos y ejecutar solicitudes. Usé CGI/FastCGI en el servidor.

El protocolo binario que diseñé es bastante simple (siempre mejor) y divide las transferencias grandes en fragmentos de un tamaño definido por el usuario (alrededor de 600k parece estar bien). Cada fragmento tiene un encabezado seguido de los datos.

Aunque este protocolo se puede usar para transmitir cualquier tipo de datos, generalmente se usa para datos de estilo de base de datos como sugiere su pregunta. Para acomodar esto, decidí usar un enfoque de filas/columnas para el diseño. Los datos se almacenan una fila a la vez, lo que significa que cada una de las columnas se almacena para la fila uno, luego todas las columnas para la fila 2 ... fila n.

El formato de los datos de una sola columna es:

' 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  

(en C, un BYTE es CHAR)

Esto significa que cada columna tiene un descriptor de tipo de datos. Todos los tipos de datos se pueden representar con:

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

Estos tipos de datos coinciden con los tipos de datos fundamentales de SQLite y son numéricamente equivalentes a la enumeración de tipos de datos fundamentales de SQL3.

En este diseño, si un campo está vacío (NULO), entonces solo ha tomado 5 bytes para almacenarlo. Si un campo tiene 200 bytes de texto, por ejemplo, solo se necesitan 205 bytes para almacenarlo. El mayor beneficio está en el análisis de los datos, ya que se pueden omitir columnas sin leer los 200 bytes para encontrar algún carácter de terminación.

El encabezado del fragmento debe contener cosas como el número de filas, el número de columnas, el total de bytes, etc.

La implementación requiere escribir envoltorios SQLite/MYSQL para esta funcionalidad. Utilizo el protocolo BINARY exclusivamente, lo que lleva un poco de tiempo, pero básicamente necesita las siguientes funciones:Lado del cliente:SendRequest() - Envía la solicitud, espera la respuesta

Lado del servidor:ProcessRequest() - Recibe la solicitud, la procesa y devuelve la respuesta

En mi caso, la respuesta puede ser !00 MB de datos o más. Recupero todo el conjunto de datos de MySQL y lo guardo en el disco del servidor. Luego, devuelvo un fragmento vacío que contiene las métricas del conjunto de datos. Luego, el cliente solicita el conjunto de datos en fragmentos de 600k, uno por uno. Si se pierde la conexión, simplemente continúa donde se quedó.

Finalmente, el conjunto de datos era principalmente texto (nombres, direcciones, etc.) tan listo para la compresión. La seguridad fue un problema muy importante en este caso, por lo que el cifrado era esencial. Esto se vuelve un poco más complicado de implementar, pero básicamente se comprime todo el fragmento, se rellena a una longitud que es un múltiplo de los cifrados de bloque BLOCKSIZE y se cifra.

En el proceso de todo esto, escribo una clase de creación de cadenas muy rápida, una implementación de cifrado AES en ASM y una biblioteca FastCGI completa (www.coastrd.com)

Entonces, como dije, no es trivial. Estaré poniendo a disposición esta biblioteca pronto. Si quieres comprobarlo, envíame un correo electrónico.

Una vez que tenga la comunicación escrita, puede comenzar a diseñar la sincronización. Usaría un hash para cada registro o una bandera booleana simple. Si algo cambia en el servidor, simplemente envíe el registro completo y sobrescríbalo en el lado del cliente (asumiendo que está intentando mantener los clientes sincronizados...)

Si escribe la suya propia, ¡por favor publique aquí sobre su experiencia!

PD. Considere cambiar el título para que sea más fácil de buscar. Tal vez algo como:

"Sincronización de una base de datos de cliente SQLite con una base de datos de servidor MySQL"