Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Sincronizando um banco de dados cliente SQLite com um banco de dados do servidor MySQL


Bem, você percebe que este é um problema não trivial. Eu escrevi uma biblioteca para fazer isso para um aplicativo comercial no ano passado e levou cerca de 6 meses para chegar onde eu estava feliz com isso.

Deixando de lado o argumento de usar a porta 80 e HTTP (TCP/IP) para evitar problemas de firewall e suporte, você precisa projetar um protocolo. Como meu projeto era muito intensivo em dados, usei um protocolo binário (em vez do xml inchado) que poderia lidar com qualquer dado. Eu também queria que fosse bidirecional para que eu pudesse inserir dados e também executar solicitações. Eu usei CGI/FastCGI no servidor.

O protocolo binário que eu projetei é bastante simples (sempre melhor) e divide grandes transferências em pedaços de um tamanho definido pelo usuário (cerca de 600k parece ser bom). Cada pedaço tem um cabeçalho seguido pelos dados.

Embora esse protocolo possa ser usado para transmitir qualquer tipo de dados, normalmente ele é usado para dados de estilo de banco de dados, como sugere sua pergunta. Para acomodar isso, decidi usar uma abordagem de linhas/colunas no design. Os dados são armazenados uma linha de cada vez, o que significa que cada uma das colunas é armazenada na linha um, depois todas as colunas na linha 2 ... linha n.

O formato de dados de uma única coluna é:
' 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  

(em C, um BYTE é CHAR)

Isso significa que cada coluna tem um descritor de tipo de dados. Todos os tipos de dados podem ser representados com:
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

Esses tipos de dados coincidem com os tipos de dados fundamentais do SQLite e são numericamente equivalentes à enumeração de tipos de dados fundamentais do SQL3.

Neste design, se um campo estiver vazio (NULL), você terá apenas 5 bytes para armazená-lo. Se um campo tem 200 bytes de texto, por exemplo, são necessários apenas 205 bytes para armazená-lo. O maior benefício é analisar os dados, pois pular colunas pode ser feito sem ler todos os 200 bytes para encontrar algum caractere final.

O cabeçalho Chunk deve conter coisas como número de linhas, número de colunas, total de bytes etc etc. Se você usar DWORDs (inteiros não assinados de 64 bits), o limite teórico para um pedaço é 4,2 GB, o que deve ser suficiente mesmo para transmissão em rede local.

A implementação requer escrever wrappers SQLite/MYSQL para esta funcionalidade. Eu uso exclusivamente o protocolo BINARY, o que leva um pouco de tempo, mas você precisa essencialmente das seguintes funções:Client Side:SendRequest() - Envia solicitação, aguarda resposta

Lado do servidor:ProcessRequest() - Recebe a solicitação, processa e retorna a resposta

No meu caso, a resposta pode ser !00 MB de dados ou mais. Eu recupero todo o conjunto de dados do MySQL e o salvo em disco no servidor. Em seguida, retorno um pedaço vazio que contém as métricas do conjunto de dados. O cliente então solicita o conjunto de dados em pedaços de 600k, um por um. Se a conexão for perdida, ele apenas retoma de onde parou.

Finalmente, o conjunto de dados era principalmente texto (nomes, endereços, etc.) tão maduro para compactação. A segurança era um problema muito grande neste caso, então a criptografia era essencial. Isso fica um pouco mais complicado de implementar, mas basicamente você compacta o pedaço inteiro, preenche um comprimento que é um múltiplo das cifras de bloco BLOCKSIZE e o criptografa.

No processo de tudo isso, escrevo uma classe de construtor de string muito rápida, uma implementação de criptografia AES no ASM e uma biblioteca FastCGI inteira (www.coastrd.com)

Então, como eu disse, não trivial. Estarei disponibilizando esta biblioteca em breve. Se quiser conferir, me mande um e-mail.

Depois de ter a comunicação escrita, você pode começar a projetar a sincronização. Eu usaria um hash para cada registro ou um sinalizador booleano simples. Se alguma coisa mudar no servidor, basta enviar o registro inteiro e sobrescrevê-lo no lado do cliente (supondo que você esteja tentando manter os clientes sincronizados...)

Se você escrever o seu próprio, por favor, poste aqui novamente sobre sua experiência!

PS. Considere alterar o título para ser mais amigável à pesquisa. Talvez algo como:

"Sincronizando um banco de dados cliente SQLite com um banco de dados do servidor MySQL"