Sincronização de Bases de Dados remotas

BraBo

Banido
Já há algum tempo que tenho pensado nisto, apesar do tempo dispendido ter sido muito reduzido.

Gostaria de ter uma ideia de como sincronizar duas bases de dados remotas (entre si) sem aceder aos seus logs, ou seja, ao ligar um cliente (com uma base de dados) a um servidor (com outra base de dados), as duas saberem que dados foram inseridos/alterados e onde.

A ideia era fazer algum processamento "local" nos dados remotos, usando para isso uma replica da base de dados remota. Ex:
Código:
Dados->SincronizaDB(); // Retira os dados remotos e faz update/insert dos locais
Dados->ProcessaDadosDB(); // Processa dados locais
Dados->SincronizaDB(); // Faz update novamente aos dados alterados
Não estou à procura do algoritmo, mas sim da lógica/principio ou link para uma página com a lógica/principio.
 
Oi pessoal
Devem existir n formas de fazer isso, sinceramente nunca me dediquei muito a investigar sobre as melhores formas de fazer o que solicitas, no entanto, em tempos estive envolvido num projecto que tinha um requisito similar, e resolvemos a coisa da seguinte forma. (a ver se me consigo explicar sem ligar o complicador...:cwm3:)

A base de dados do servidor tinha uma view que fornecia ao cliente os dados que tinham sido alterados desde a ultima vez que esse cliente tinha sacado os dados. No entanto isso partia do pressuposto que a tabela tinha um campo data que indicava o timestamp da alteração/criação do registo.

O cliente importava os dados dessa view e fazia com eles o que pretendia.

De seguida exportava os dados novamente para o servidor com as alterações que tinha feito.

As operações de leitura e escrita dos clientes eram registadas numa tabela no servidor por forma a que este soubesse sempre quais os dados que o cliente nao tinha ainda, ou que tinham sido alterados entretanto. Essa tabela servia como condição à view que falei no inicio por forma a que esta determinasse quais os registos que deveria enviar ao cliente...

Confuso? :wscared: um pouco... mas é um problema complexo, e nem sequer estou a entrar em linha de conta com o Merge de dados que dá outro livro...

Abraço
 
Eu já tinha pensado num sistema similar ao que descreveste.

Pensei em ter não uma tabela com as alterações feitas, mas sim um campo com o timestamp da alteração de registo em cada uma das tabelas. Mas isto levou-me a um empasse... Se o processamento dos dados de uma tabela for feito em mais do que um lado, como se vai sincronizar os mesmos?!?!?!

Imagina o seguinte exemplo:
Tens um "último registo" com o timestamp de 111111111 em ambos os lados (cliente e servidor). O cliente começa a processar os dados e ao alterar o registo atribui o novo timestamp de 111111234. Mas entre a sincronização do registo com o servidor e o seu processamento no cliente, este foi alterado no servidor tendo adquirido um timestamp de 111123456 que é maior ao processado no cliente...
Desta forma, no cliente o registo processado tem um timestamp de 111111234 e no servidor um de 111123456 que é superior (mais recente), logo já é um bico de obra saber por qual optar, ainda por cima quando mais registos em mais tabelas poderão estar dependentes dessa alteração....

Tudo isto sem falar que pode haver mais do que 1 cliente a processar informação...

Será que não há um método mais eficaz de fazer isto, sem ter de cortar a alteração de dados de um dos lados?!?!
 
Sim, é um facto. No entanto não tivemos esse problema uma vez que a responsabilidade da gestao dos timestamps era feita exclusivamente no servidor, ou seja, e expondo por passos:

1-O cliente sincroniza a sua base de dados local com os dados que o servidor disponibiliza. O servidor regista que aquele cliente específico sincornizou a sua base de dados local naquela data (server time), por exemplo 11111111

2-O cliente desliga-se do servidor e faz o que tem a fazer.

3-O cliente envia o resultado do seu trabalho ao servidor. O servidor verifica a data da ultima sincronização daquele cliente (11111111 no nosso caso) com a data actual (do servidor, não do registo, por exemplo 44444444) e para cada registo verifica se alguem entretanto nao terá criado uma versão mais recente (data do registo entre 11111111 e 44444444). Se não existir nova versão o registo é aceite caso contrário o cliente é solicitado para resolver a concorrencia dos dados. O registo quando é aceite fica com a data em que a sincronização é feita (44444444 no nosso caso), ou seja sempre com datas de servidor.

O cliente pode ter colocado um timestamp no registo de acordo com a data em que o registo foi processado, mas o servidor nao a toma em linha de conta.
A unica responsabilidade que o cliente tem é saber quais os registos que alterou e envia-los ao servidor. Toda a responsabilidade da gestão de versões, histórico e detecção de concorrência é feita no servidor, o que permitiu que o sistema funcionasse de forma robusta quer no que diz respeito à concorrencia como à própria integridade de dados.

Abraço
 
Há algumas coisas que não entendi na tua explicação...
-> Como é que o cliente sabe os registos a enviar para o servidor?!?!? A não ser que ele tenha apenas a Base de Dados local para referência, e não a usa para fazer updates/inserts/deletes aos seus registos, sendo que então ele precisa sempre da confirmação do servidor para poder gravar as alterações, ou seja, ligação ao servidor para confirmar as operações.

-> Imagina que o cliente altera 50 registos, sendo os 40 últimos updates aos registos locais, estando sempre cada um dependente do anterior.
Ao fazer a sincronização com o servidor, este retorna um hipotético erro ao décimo registo, como é que repões os valores anteriores, já que se não repuseres, os dados irão estar corrompidos?!?!?

Abraço.
 
Vamos ver se eu percebi.

Como é que o cliente sabe os registos a enviar para o servidor?
No nosso caso a estratégia que utilizamos foi a seguinte:
Como o timestamp que do registo que vinha do servidor nao tinha significado no lado do cliente, este campo ficava a NULL. Se o cliente fizesse um update ou insert de um registo colocava um timestamp, logo, os registos a exportar para o servidor eram aqueles que tinha o timestamp diferente de NULL. Em vez do timestamp podes optar por uma flag que indica se o registo foi ou nao alterado pelo cliente. De notar que no nosso caso, por uma questão de histórico, não se fazia delete a nenhum registo, os registos eram desactivados, nunca removidos. Se pretenderes que ele possa ser removido o cliente nao pode fazer o delete directamente porque depois não consegues informar o servidor da remoção do registo, deves sim, marcar o registo como "Para apagar" e fazeres o delete depois da confirmação do servidor (Nota: Usamos transacções distribuidas nestas operações)

como é que repões os valores anteriores, já que se não repuseres, os dados irão estar corrompidos?
Depende do erro... e acredita que essa foi a maior dor de cabeça que tivemos. Por exemplo:
Querias exportar um registo que dependia de um registo pai que ja nao existe ou cujo código foi alterado. Nesse caso era solicitado ao cliente que escolhesse outro registo pai ou para criar um novo.

Chegaste à conclusao que as alterações que fizeste estão completamente incoerentes com o estado actual da BD. Tinhas a possibilidade de fazer um rolback à transacção e refazer a importação.

Esta solução é a mais simples, mas tem um problema. Uma vez que a exportação pode ser interactiva e é feita num contexto transaccional, bloquia a base de dados... (No nosso caso isso nao era problema uma vez que o acesso era controlado e espaçado no tempo). Para mitigares esse problema podes optar pela estratégia do "pedido de alteração" mas isso é bem mais complicado...

Não sei se respondi as tuas questões, este é um assunto que tem pano para mangas...
já agora, o SGBD do cliente era SQLServer enquanto que o do servidor era Informix. Se ambos fosses SQLServer teria estudado a possíbilidade de utilizar as suas funcionalidades de Replicação.

Abraço
 
Última edição:
Karakatoa disse:
... Como o timestamp que do registo que vinha do servidor nao tinha significado no lado do cliente, este campo ficava a NULL
Então como saber quais os registos a retirar do servidor por parte do cliente?!?!?! Não havia nenhum tipo de referência??! Pensei que o cliente enviasse o ultimo timestamp retirado do servidor para que o servidor retornasse todos os registos posteriores a essa referência!...

Karakatoa disse:
De notar que no nosso caso, por uma questão de histórico, não se fazia delete a nenhum registo, os registos eram desactivados, nunca removidos. Se pretenderes que ele possa ser removido o cliente nao pode fazer o delete directamente porque depois não consegues informar o servidor da remoção do registo, deves sim, marcar o registo como "Para apagar" e fazeres o delete depois da confirmação do servidor (Nota: Usamos transacções distribuidas nestas operações)
Exactamente, faz todo o sentido. Mas se tiveres mais do que um cliente como é que fazes?!?!
Ex:
-> Cliente1 retira registo do Servidor para máquina local
-> Cliente2 retira registo do Servidor para máquina local
-> Cliente1 marca registo como "Para Apagar"
-> Cliente1 comunica a intensão de apagar registo ao Servidor
-> Servidor apaga registo e re-envia a confirmação ao Cliente1
-> Cliente1 apaga registo na máquina local
-> Cliente2 altera o registo mais um segundo registo com base nessa primeira alteração
-> Cliente2 comunica alterações com o Servidor
-> Servidor não faz P*** de ideia do que fazer com aquilo, pois os dados a alterar não existem...

O problema é mesmo a sincronização, e não própriamente a transacção entre duas bases de dados.
A mesma questão se pode pôr, se os dados podem ser processados quer no Servidor quer no Cliente. Este último pode estar a processar dados que já não existem no lado do Servidor, o que pode ser muito grave.

Karakatoa disse:
Esta solução é a mais simples, mas tem um problema. Uma vez que a exportação pode ser interactiva e é feita num contexto transaccional, bloquia a base de dados... (No nosso caso isso nao era problema uma vez que o acesso era controlado e espaçado no tempo). Para mitigares esse problema podes optar pela estratégia do "pedido de alteração" mas isso é bem mais complicado...
Como assim "pedido da alteração"?!?!?

Karakatoa disse:
Não sei se respondi as tuas questões, este é um assunto que tem pano para mangas...
já agora, o SGBD do cliente era SQLServer enquanto que o do servidor era Informix. Se ambos fosses SQLServer teria estudado a possíbilidade de utilizar as suas funcionalidades de Replicação.
A ideia inicial que tive (quando comecei a pensar nisto) era tentar sincronizar dados de duas bases de dados localizadas remotamente usando para isso XML por exemplo, logo os DBMS's não seriam relevantes pois os acessos aos mesmos não seriam directos... Mas a sincronização não seria em tempo real, ex:
Se duas filiais quiserem comunicar com a sede fazendo o update da informação diária, usariam uma tarefa agendada para determinada hora com menos concorrência (internet/postos trabalho). O grande problema, é fazer coincidir o trabalho das três areas geográficas numa só base de dados (sede)...
 
hummmm... O que pretendes é diferente do que eu sopunha, isso porque a nossa sincronização de dados do cliente para o servidor era feita de forma interactiva, ou seja, sempre que ocorriam conflitos o utilizador era convidado a resolve-las, no entanto, no nosso caso, estatisticamente falando, a esmagadora maioria das operações corriam sem confiltos.
Existiam alguns algoritmos que permitiam ao servidor tomar algumas decisoes aquando conflito de dados, mas a resposabilidade de resolução era sempre do cliente.

como saber quais os registos a retirar do servidor por parte do cliente?
Não era o cliente que decidia isso. O servidor usava uma view para disponibilizar apenas os registos que o cliente precisava.

"pedido da alteração"?
Utiliza-se para um processamento assincrono por parte do servidor, ou seja, as tabelas do servidor nao sao alteradas no momento. O que é posto no servidor é um pedido de alteração do registo. Esta solução é util quando é pretendido incluir um workflow por detrás desse pedido, mas apenas serve para utilizações muito especificas devido à sua complexidade.

abraço
 
Back
Topo