Como comunicar um sistema Desktop em rede de lojas

Cara, antes de mais nada, leia este artigo. Do contrário, você corre um grande risco de começar a correr atrás do próprio rabo …

Na verdade , seguindo esta última lógica, o sistema não seria basicamente um sistema com uma base de dados distribuída…mas sim um sistema com redundância de dados, no qual eliminaria várias formas de possíveis falhas… inclusive a falha na internet… se assim como o mecanismo automático de atualização, poderia fazer uma sincronização manual…

Voltando a discução deste tópico… postarei aqui o que foi implementado…e como funcionou

Implementei da maneira mais prática para verificar como o sistema se comportaria…
(Não sei se seria a mais correta para este caso, mas é bom colocar em prática para ver realmente como funciona)

Implementei da seguinte forma…

Na loja matriz fica a base de dados e a filial só fica instalado o sistema no qual acessa via internet a base de dados situada na matriz…
Então o sistema associa cada registro armazenado a sua filial, cada produto tem sua filial, cada venda tem sua filial, facilitando assim consultas, relatórios e visulizações pelos funcionarios…

*Um problema que notei é a lentidão tanto nas consultas quanto nos cadastros quando acessado via internet… (não instalei ainda no cliente, porém montei um server aqui e acessei o sistema de uma outra rede através do notbook)
Bom onde estava instalado a base de dados tem uma banda razoável de internet uns 5 M e de onde acessei o sistema tem uma banda de 2 M…portanto, creio que não seja o problema de baixa taxa de transferencia da internet.

*Em rede local não possui essa lentidão (claro he he he)

Estou pensando seriamente em fazer como citado em posts anteriores…em instalar uma base de dados em cada loja e fazer um módulo de “sincronização” das bases de tempos em tempos…creio que resolveria os problemas de queda repentina de internet e o problema de lentidão do sistema…

O que voces acham…?

Obs:Meu sistema é desktop, (a pedido do cliente) claro que se fosse um sistema web seria bem mais prático e sem tantos problemas…

lendo todos os posts eu senti falta de 1 pergunta:

O que precisa ser sincronizado ?

a necessidade de trabalhar com matriz e filial levantou quais requisitos ? Quais informações a filial precisa passar para matrix e vice-versa ? Com que frequência ?

A menos que você esteja lidando com lojas que compartilhem um estoque único (a filial vende, mas quem entrega é a matriz) eu não vejo motivo para que a comunicação seja atômica. E se for esse mesmo o caso, você pode trabalhar com algumas sincronizações diárias, sei lá, duas ou três vezes por dia, ou então uma vez por dia fora do horário do expediente.

Se a filial não tem dependência da matriz para efetuar as atividades, então sugiro que trabalhe com os dados localmente e depois em um determinado horário faça os sincronismos necessários.

Ainda assim podem existir casos onde seja necessário uma comunicação síncrona, mas você reduz muito a dependência da matriz pois apenas precisaria consumir serviços em algumas situações e não passar um código de barras e aguardar a matriz devolver o nome e o valor do produto.

Isso mesmo…

Claro que o cliente quer chegar no final do dia…entrar no sistema e ver o que foi vendido na matriz e filiais, quanto de estoque tem em cada uma e gerar relatórios de movimentação, custos, etc… mas no fim do dia…

Estava pesquisando sobre a tal 'sincronização" e estou vendo que vou ter dor de cabeça com isso,me refiro as chaves primárias …

Isso mesmo…

Claro que o cliente quer chegar no final do dia…entrar no sistema e ver o que foi vendido na matriz e filiais, quanto de estoque tem em cada uma e gerar relatórios de movimentação, custos, etc… mas no fim do dia…

Estava pesquisando sobre a tal 'sincronização" e estou vendo que vou ter dor de cabeça com isso,me refiro as chaves primárias …

[/quote]

usa chave composta, no servidor da matriz vc faz uma parte da chave AUTOINCREMENT ou um identificador para a filial e na outra parte da chave a chave da tabela da filial

Isso mesmo…

Claro que o cliente quer chegar no final do dia…entrar no sistema e ver o que foi vendido na matriz e filiais, quanto de estoque tem em cada uma e gerar relatórios de movimentação, custos, etc… mas no fim do dia…

Estava pesquisando sobre a tal 'sincronização" e estou vendo que vou ter dor de cabeça com isso,me refiro as chaves primárias …

[/quote]

Olha, isso pode ser mais fácil ou mais difícil, dependendo de como você trabalha com chaves primárias e quais são as entidades que precisam de sincronização.

Na minha opinião, a melhor abordagem para trabalhar com entidades é usar, sempre que possível, chaves simples, de auto-incremento. E nunca usar chaves naturais como PK, justamente porque em dado momento, um registro pode ter sua chave natural alterada, trazendo complicações na hora de fazer merge entre bases de dados ou então alterar o valor da PK.

Olá a todos…
Continuando…

Então… a chave composta seria uma alternativa… porém terei que modificar todo o sistema para trabalhar com chaves compostas em vez das de autoincremento que atualmente ele está trabalhando…
Além disso…estou fazendo todo o mapeamento das tabelas no hibernate…e pelo que andei lendo…não é muito prático a utilização de chaves compostas no hibernate…não sei se estou enganado…

Mas seguindo a idéia que me foi passada

Ok…mas então ficaria chaves diferentes no sistema da filial e matriz…

*Uma outra alternativa, seria dividir a geração das chaves…continuando com o auto incremento, porém em faixas de numeração diferentes para cada filial…
Ex.: Matriz trabalharia com cadastros de produtos de 0 a 1000.000, na filial 1 trabalharia com a numeração de 1000.001 a 2000.000 e assim por diante…isso valeria para todas as tabelas do sistema … assim quando fizesse a sincronização nunca daria conflito de chaves… e os bancos ficariam réplicas idênticas…

*Mais uma alternativa seria usar na geração de chaves um dígito identificador … os que iniciarem com 1 é da matriz os que iniciarem com 2 é da filial 1 e assim por diante…
Ex: cdProduto = 10000000025 seria um produto da matriz e cdProduto 200000025 seria um produto da filial1

Seria uma boa opção? sim? não?

[quote=leopoldof]Olá a todos…
Continuando…

Então… a chave composta seria uma alternativa… porém terei que modificar todo o sistema para trabalhar com chaves compostas em vez das de autoincremento que atualmente ele está trabalhando…
Além disso…estou fazendo todo o mapeamento das tabelas no hibernate…e pelo que andei lendo…não é muito prático a utilização de chaves compostas no hibernate…não sei se estou enganado…

Mas seguindo a idéia que me foi passada

Ok…mas então ficaria chaves diferentes no sistema da filial e matriz…

*Uma outra alternativa, seria dividir a geração das chaves…continuando com o auto incremento, porém em faixas de numeração diferentes para cada filial…
Ex.: Matriz trabalharia com cadastros de produtos de 0 a 1000.000, na filial 1 trabalharia com a numeração de 1000.001 a 2000.000 e assim por diante…isso valeria para todas as tabelas do sistema … assim quando fizesse a sincronização nunca daria conflito de chaves… e os bancos ficariam réplicas idênticas…

*Mais uma alternativa seria usar na geração de chaves um dígito identificador … os que iniciarem com 1 é da matriz os que iniciarem com 2 é da filial 1 e assim por diante…
Ex: cdProduto = 10000000025 seria um produto da matriz e cdProduto 200000025 seria um produto da filial1

Seria uma boa opção? sim? não?

[/quote]

Cara, eu acho que trabalhar com chaves compostas só vai de trazer dor de cabeça.
Você tem que pensar que o sistema é um só! Sendo assim, entidades são únicas para o sistema todo. Por exemplo, se você tem um cadastro de clientes, por exemplo Cliente{id:1, nome:João} ele tem que ser único para todo o sistema, independentemente de onde ele foi cadastrado. Ou seja, você tem que pensar no banco da filial apenas como um cache.

Eu acho que só compensa incluir um campo para identificar se uma entidade é da matriz ou da filial em entidades onde isso faz realmente sentido, como no estoque, registro de vendas, ou seja, nas movimentações de maneira geral, e mesmo nestes casos, eu não colocaria esse campo como parte da PK. Por outro lado, acho que não compensa fazer essa distinção em cadastros como clientes, fornecedores, até mesmo produtos.

Só uma pergunta, o seu cadastro de produtos é separado do controle de estoque, certo ?

[quote]Cara, eu acho que trabalhar com chaves compostas só vai de trazer dor de cabeça.
Você tem que pensar que o sistema é um só! Sendo assim, entidades são únicas para o sistema todo. Por exemplo, se você tem um cadastro de clientes, por exemplo Cliente{id:1, nome:João} ele tem que ser único para todo o sistema, independentemente de onde ele foi cadastrado. Ou seja, você tem que pensar no banco da filial apenas como um cache.

Eu acho que só compensa incluir um campo para identificar se uma entidade é da matriz ou da filial em entidades onde isso faz realmente sentido, como no estoque, registro de vendas, ou seja, nas movimentações de maneira geral, e mesmo nestes casos, eu não colocaria esse campo como parte da PK. Por outro lado, acho que não compensa fazer essa distinção em cadastros como clientes, fornecedores, até mesmo produtos.[/quote]

Concordo…só que daí ocorreria um problema…
Citando o exemplo de clientes…claro que … o cliente vai ter um só registro para todas as filiais…
Mas veja a seguinte situação…
O leo chega na filial1 e faz o seu cadastro e efetua uma compra… o código de cliente dele é 25…por consequencia, no registro de venda, o cdCliente vai ser 25, nas contas a receber vai ser 25, no recebimento vai ser 25 , e assim por diante… e se quando for sincronizar com a matriz…já tiver na matriz um cliente cadastrado com o código 25??? …vai ter que mudar sua codificação em várias tabelas antes de inserir os novos registros na matriz… e a partir daí acontece outro problema… pois o funcionario sabe que o leo tem o codigo 25 hoje e que amanhã ele pode der o 30…entende…

O mesmo pode acontecer para as vendas… hoje a venda pode ser a 1550 e amanhã ele pode ser a 1552 por caso da sincronização…(se não tiver um identificador de filial)

Claro que em casos como nas tabelas de clientes e fornecedores e outras não prescisa ter distinção de filial… só ficaria essa numeração no ID para não dar conflito de PK na hora da sincronização e sempre manteria a mesma numeração independente da filial em que está… e nunca daria conflito e mudança de PK…

Pior que não… atualmente está tudo numa tabela só… tem uma coluna a mais no produto em que informa a quantidade… tenho que mudar isso também…separar para não dar redundância de registros… mas estou indo por partes…he he eh… primeiro a parte de comunicação Matriz-Filiais

E WebService? Nada impede de você ter um cliente desktop acessando um servidor que disponibiliza as suas operações de persistência e backend através de serviços. Acho muito mais simples e flexível do que sincronizar bds…

Seria uma boa opção…
Mas não consigo visualizar a lógica da idéia de webservice sujerida…
Como ficaria?

A filial enviaria para o WS os registros alterados e a Matriz requisitaria do WS os registros alterados?
Depois seria feito o caminho inverso?

Eu pensei em um servidor na matriz somente, todos acessam o mesmo WS consequentemente com a mesma base… Quando um registro do banco é alterado, todos os clientes automaticamente estarão atualizados pois todos se conectam na mesma base através dos mesmos serviços…

Ué, mas aí ele até piora o problema de latência que ele tem. Ao fazer a comunicação com o banco de dados, os dados são trocados em um formato binário, que é muito mais econômico em termos de banda de rede do que um protocolo baseado em texto como o HTTP/JSON/XML.

Acho que a melhor maneira de resolver esse problema da numeração é reservar faixas de numeração para cada filial. Não sei se o banco de dados que você usa suporta esse recurso nativamente, caso contrário, você vai ter que fazer esse controle manualmente através de uma tabela auxiliar.

Ué, mas aí ele até piora o problema de latência que ele tem. Ao fazer a comunicação com o banco de dados, os dados são trocados em um formato binário, que é muito mais econômico em termos de banda de rede do que um protocolo baseado em texto como o HTTP/JSON/XML.

Acho que a melhor maneira de resolver esse problema da numeração é reservar faixas de numeração para cada filial. Não sei se o banco de dados que você usa suporta esse recurso nativamente, caso contrário, você vai ter que fazer esse controle manualmente através de uma tabela auxiliar.[/quote]
Piora o problema?

E se o objeto for compactado depois de serializado (tanto na ida como na volta)? Com GZIP por exemplo… Tenho sistemas assim e rodando em uma rede lenta e a performance bate de longe um sistema web… E como eu disse antes, você não fica preso a uma arquitetura de um banco de dados específico

Primeiramente quero agradecer as opiniões, ajuda, sujestões…estão sendo de grande valia…pois estou chegando a conclusões concretas…problema está saindo do papel e está quase transformando em solução he he he…e espero que esse tópico ajude muita gente mais adiante que estiver implementando algo parecido ou passando por alguma dificuldade parecida…

Então vamos lá…

Mas esse esquema de webservice seria para sincronização ou para a comunicação direta com a base de dados…??

Se for para comunicação direta, a cada registro, ele enviaria para a base central? a cada consulta seria feita uma requisição?

Pois fiz um teste aqui se conectando diretamente na base de dados central através de uma rede externa a da base…e fica lento para listagens, etc…
Se conectado diretamente fica lento… será que com WS não ficaria ainda mais? Somente pergunto…pois não manjo muito de WS…

Se for para sincronização…seria uma boa até…porém teria que ter um terceiro elo na ligação entre matriz e filial para isso… uma máquina em que momento em momento matriz e filiais ficariam enviando as modificações e requisitando as modificações feitas por outras filiais…

Como ficaria a lógica… Seria como mensagens compactadas?

O banco que estou usando atualmente é o postgres…e para a geração das PK uso sequences

Como seria “suportar o recurso de reserva de faixas nativamente”? Seria setar na sequence de cada filial o início e fim de numeração? ou trabalhar com triggers ou functions??

Ué, mas aí ele até piora o problema de latência que ele tem. Ao fazer a comunicação com o banco de dados, os dados são trocados em um formato binário, que é muito mais econômico em termos de banda de rede do que um protocolo baseado em texto como o HTTP/JSON/XML.

Acho que a melhor maneira de resolver esse problema da numeração é reservar faixas de numeração para cada filial. Não sei se o banco de dados que você usa suporta esse recurso nativamente, caso contrário, você vai ter que fazer esse controle manualmente através de uma tabela auxiliar.[/quote]
Piora o problema?

E se o objeto for compactado depois de serializado (tanto na ida como na volta)? Com GZIP por exemplo… Tenho sistemas assim e rodando em uma rede lenta e a performance bate de longe um sistema web… E como eu disse antes, você não fica preso a uma arquitetura de um banco de dados específico[/quote]

Ué, mas aí você está comparando um protocolo Web compactado com um protocolo Web não compactado, daí a velocidade tende a ser maior mesmo. Pelo que eu entendi, a aplicação do nosso colega conecta-se diretamente com o banco de dados através da Internet, ou seja, não há nenhuma camada ou protocolo intermediário entre os dois. Nesse caso, eu dúvido muito que um protocolo Web, mesmo que compactado com GZIP, seja mais econômico do que protocolos nativos dos bancos de dados.

Nos sistemas que desenvolvemos aqui na empresa utilizamos o mesmo banco que você utiliza, PostgreSQL, e acredite, já tentamos sincronizar bases através do slony e (na época, uns 4 a 5 anos atrás) foi uma dor de cabeça enorme…

Tínhamos o problema de performance e nossos sistemas eram desktop, o que fazer?

  1. Tentamos conexão direta ao banco (sem camada intermediária): Somente o banco ficava no servidor e os clientes rodavam a aplicação que se conectava diretamente ao banco.
  • Vantagem: Fácil implementação.
  • Desvantagens: Lentidão em pesquisas, inviabilidade de controle de transações (impossível tratar commits e rollbacks se quem faz o acesso direto não é o próprio servidor), baixa segurança e tolerância à falhas.
  1. Sincronismo de bases: Acredito que seria talvez a forma mais performática, como o rmendes08 comentou. Não implementamos a solução por completo devido à inviabilidade de reconhecimento das bases pois somente o servidor tinha IP fixo e não entrava em questão mascarar o IP através de serviços como NoIP ou DynDNS.
  • Vantagem: Performance, se levarmos em conta os protocolos nativos (que vai depender de banco para banco). Altamente escalável e tolerante à falhas, se uma das bases parar, as outras continuam normalmente.
  • Desvantagem: Difícil implementação (acredito eu, pelo que posso falar da época que lidei nisso). Inflexibilidade, se levarmos em conta que para cada banco de dados o processo é diferente. Todas as bases devem se conhecer diretamente (o que significa cada uma delas ter visibilidade na WAN)
  1. Web service: É a solução que encontramos e usamos até hoje. Atualmente utilizamos o Axis e implementamos nosso próprio ‘protocolo’ para comunicação, que exige autenticação, controle de sessão própria (para os clientes Desktop), pool de conexões, criptografia e compactação dos bytes serializados. Só para ter uma ideia, temos base de dados com fotos cadastradas diretamente no banco e acessadas por clientes em diferentes cidades e a performance é muito boa (levando em conta a compactação)
  • Vantagens: Controle unificado de transações, Pool de conexões, acesso à banco local, segurança, maior controle devido ao fato de você poder criar os seus modelos e padrões de conexão. Perfomance boa e consistente em redes lentas através do reenvio de pacotes implementados do jeito que você precisa. Escalável.
  • Desvantagem: Necessita servidor de aplicação no servidor. Por não ser tolerável à falhas, deve ter controle de contingência se o servidor cair.

Claro, isso na minha opinião levando em conta a experiência que tive com esses 3 modelos.

Nesse caso do WS , o que não entendo é como funcionaria a parte de transferência de dados entre a filial e a matriz, pois teoricamente seria mas lento com WS do que se eu setar na filial o ip direto do servidor bd na matriz. Mas isso teoricamente…não posso afirmar nada concreto, pois só testei conexão direta…

Tipo… se por exemplo eu quisesse fazer uma consulta de clientes, me retornando uns 3000 registros… qual seria a forma?
Seria algo assim?

  1. Filial gera, compacta e manda requisição de pesquisa para a matriz,
    2)A matriz recebe, descompacta efetua a pesquisa, gera a mensagem de resposta, compacta e envia
    3)Filial recebe a mensagem de resposta, descompacta e envia os dados para a tela de visualização de pesquisa

Seria mais ou menos isso…? Então o segredo da velocidade estaria na compactação dos dados antes do envio??? Pois o volume a ser enviado seria brutalmente reduzido durante a compactação

[quote=leopoldof]Nesse caso do WS , o que não entendo é como funcionaria a parte de transferência de dados entre a filial e a matriz, pois teoricamente seria mas lento com WS do que se eu setar na filial o ip direto do servidor bd na matriz. Mas isso teoricamente…não posso afirmar nada concreto, pois só testei conexão direta…

Tipo… se por exemplo eu quisesse fazer uma consulta de clientes, me retornando uns 3000 registros… qual seria a forma?
Seria algo assim?

  1. Filial gera, compacta e manda requisição de pesquisa para a matriz,
    2)A matriz recebe, descompacta efetua a pesquisa, gera a mensagem de resposta, compacta e envia
    3)Filial recebe a mensagem de resposta, descompacta e envia os dados para a tela de visualização de pesquisa

Seria mais ou menos isso…? Então o segredo da velocidade estaria na compactação dos dados antes do envio??? Pois o volume a ser enviado seria brutalmente reduzido durante a compactação[/quote]
Exatamente, faça um modelo simples e você vai ver a diferença, mesmo não compactando os dados a velocidade é maior do que via conexão direta devido ao acesso local do WebService com o banco de dados…

Vamos supor que a filial requisite todos os produtos da matriz. O processo que realizo aqui nos sistemas é esse:

No cliente (filial):

  1. Compõe o objeto do filtro da pesquisa desejada (pode ser um objeto Produto vazio, por exemplo, indicando que você quer trazer todos os produtos);
  2. Compacta e criptografa os bytes serializados do objeto Produto;
  3. Inicia processo de envio do pacote, que nada mais é que a chamada ao método list do WebService, passando o filtro por parâmetro. Obs.: Este método list que o cliente irá consumir retorna uma lista de byte[];
  4. Se não receber resposta do servidor em um tempo X, o cliente reenvia o pacote;

Servidor (matriz):
5) WebService recebe acesso ao método list;
6) Desserializa, descompacta e descriptografa o(s) parâmetro(s) (neste caso o filtro);
7) Realiza a operação de banco de dados local (pois o BD está localhost);
8) Com a lista de produtos retornada do banco, serializa, compacta e criptografa cada objeto Produto contido na lista;
9) Inicia devolução da lista de bytes[] resultante que o cliente está aguardando;

Aqui eu abstraí, mas ainda fizemos uma validação a partir de um token do cliente, não permitindo que acessos desconhecidos.

Parece demorado? Faça um teste comparando com acesso direto e via WebService e veja você mesmo. Claro que tudo vai depender do seu algoritmo de compactação e implementação do seu WebService, mas assim você tem todas as vantagens que citei no post anterior…