Como implementar Failover e Load Balance no DataSnap 2010
Uma pergunta frequente dos desenvolvedores durante as minhas viagens pela America Latina está relacionado ao desenvolvimento multicamada com DataSnap, após explicar toda a tecnologia sempre vem a pergunta “Como implementar Failover e Load Balance neste tipo de aplicação, o que é mais do que natural.
Quando pensamos em servidores de aplicação como parte do nosso desenvolvimento multicamada temos como um dos objetivos centralizar processamento, investimento em hardware, atualizações, etc. Quando pensamos em centralizar precisamos pensar também em redundância, ou seja, se um servidor falhar outro deve assumir, também pensamos em dividir a carga de processamento, ou seja, de acordo com o volume de processamento de cada servidor no
momento redirecionamos a carga para que estiver menos sobrecarregado, chamamos isso de load balance.
Implementar essas duas características até então não era algo muito simples e exigia muito código, agora com o DataSnap 2010 a história é bem diferente.
DataSnap 2010 traz um recurso chamado HTTP Tunneling que lhe permite o controle do direcionamento da informação que está sendo enviada/recebida entre cliente e servidor. Como o próprio nome diz HTTP Tunneling, você terá que utilizar HTTP como Transporter na sua aplicação cliente para usufruir destas vantagens, o que não é um problema. Caso você queira utilizar TCP/IP na aplicação cliente, não será possível utilizar este recurso de forma simples, então recomendo utilizar HTTP.
Implementar Load Balance e Failover quer dizer criar um middleware entre a aplicação cliente e servidora, este middleware será responsável por decidir o que fazer com a informação recebida, para onde enviar, quando enviar, como enviar, etc.
Traduzindo isso para o mundo DataSnap, teremos uma aplicação cliente conectando a um servidor que neste caso chamaremos de Failover e o servidor DataSnap, o servidor de Failover será o nosso Firewall, neste post vou simular a queda de um servidor DataSnap e automaticamente a conexão será direcionada para outro servidor DataSnap.
Não é necessário fazer grandes mudanças na sua aplicação para suportar HTTP Tunneling, basicamente é ter a aplicação cliente conectando ao servidor de Failover através de HTTP, do servidor de Failover para o servidor DataSnap você poderá usar TCP/IP ou HTTP.
O servidor Failover terá apenas 2 componentes, o DSHTTPService que representa o seu Failover Server e estará conectado ao DSHTTPServiceAuthenticationManager, apenas para questões de segurança, pois quero que somente pessoas autorizadas conectem a este servidor.
Para habilitar o recurso de HTTP Tunneling você terá que implementar os eventos referente ao HTTP Service Tunnel Service, que são:
- DSHTTPService1.HttpServer.TunnelService.OnErrorOpenSession
- DSHTTPService1.HttpServer.TunnelService.OnErrorWriteSession
- DSHTTPService1.HttpServer.TunnelService.OnErrorReadSession
- DSHTTPService1.HttpServer.TunnelService.OnOpenSession
- DSHTTPService1.HttpServer.TunnelService.OnWriteSession
- DSHTTPService1.HttpServer.TunnelService.OnReadSession
- DSHTTPService1.HttpServer.TunnelService.OnCloseSession
Cada um destes eventos será executado na sua ordem natural ou quando algum erro ocorrer, os nomes de cada evento são obvios, a aplicação exemplo implementa todos estes eventos, com o objetivo de mostrar no log as informações enviadas e recebidas durante a utilização da mesma.
No caso de uma solução de Failover todos os eventos devem ser implementados, os eventos OnErrorXXX entrarão em ação quando um erro ocorrer e necessitam do conteúdo que está sendo transferido para saber o que fazer, assim sendo eles dependem dos outros eventos. Neste posto vou focar no evento OnErrorOpenSession o qual irá efetuar o redirecionamento em caso de error na abertura de sessão.
Abaixo a implementação do método chamado Redirect que esta associado ao evento OnErrorOpenSession, repare que os dados da Sessão e conteúdo são parâmetros neste método, ou seja, tudo o que precisamos para poder redirecionar a informação.
Como controle estamos utilizando o Session.UserFlag, para permitir apenas um redirecionamento e caso o Sender seja uma Exception vamos armazenar a mensagem de error. A seguir criamos um DBXProperties que contém as informações do novo servidor que deverá ser redirecionado, neste exemplo utilizei o mesmo HostName, mas a porta será a 213, ou seja, tenho outro servidor DataSnap.
A partir dai basta reabrir a sessão com as novas propriedades que a mesma será redirecionada para o novo servidor.
Você pode estar achando fácil demais, na verdade é muito fácil.
procedure TForm6.Redirect(Sender: TObject; Session: TDSTunnelSession; Content: TBytes; var Count: Integer); var DBXProperties: TDBXDatasnapProperties; Msg: String; begin if Sender is Exception then Msg := Exception(Sender).Message; Log('>>' + Msg); if Session.UserFlag = 1 then Raise Exception.Create('Backup session cannot be redirected once more.' + Msg); DBXProperties := TDBXDatasnapProperties.Create(nil); DBXProperties.Values[TDBXPropertyNames.DriverName] := 'Datasnap'; DBXProperties.Values[TDBXPropertyNames.HostName] := 'localhost'; DBXProperties.Values[TDBXPropertyNames.Port] := '213'; try try Session.Reopen(DBXProperties); Session.UserFlag := 1; Msg := 'Flow commuted to alternate resource.'; Log('>>' + Msg); except Raise Exception.Create(Msg + '. Commuting to alternate resource failed.'); end; finally DBXProperties.free; end; end;
Claro que você está curioso pra saber como funciona a execução, o que você precisa é um servidor DataSnap, servidor Failover e a aplicação cliente, neste caso utilize o próprio Data Explorer do Delphi será utilizando como aplicação cliente. A seguir os passos para executar este exemplo:
- Execute o servidor Failover, o exemplo utiliza HTTP e porta 8080
- Execute 2 instâncias do servidor DataSnap, uma na porta 211 e outra na porta 213, o servidor na porta 213 será o servidor de backup em caso de falho do servidor que está na porta 211
- Crie um DataSnap alias no Data Explorer, lembre-se de utilizar o protocolo HTTP e porta 8080
- Execute o método EchoString que aparece na lista de Procedures, passe o valor Delphi 2010 como parâmetro e execute, veja que o retorno será Delphi 2010 (Server 211)
- Feche a aplicação DataSnap server, porta 211
- Repita o passo número 4 e veja que o retorno será Delphi 2010 (Server 213)
- Veja o log no servidor Failover, você verá uma exception e o redirecionamento ocorrendo
Para facilitar o entendimento preparei um vídeo apresentando como executar este exemplo.
Você pode efetuar o download do código fonte aqui
Para outros posts relacionados ao DataSnap, clique aqui
Andreano, muito bom o post, parabéns. Só uma observação, o código fonte que você indicou não tem a fonte do Failover. No 27391 não encontrei.
Oi Rafael, baixa de novo o arquivo, acabei de atualizar. Sorry e feliz ano novo!!!
Sem problemas, obrigado Andreano, Feliz Ano Novo e Sucesso no próximo ano !!!
Muito legal este artigo. Parabéns Adriano.
Tenho apenas uma dúvida:
E se ao invés de um dos servidores de aplicação, a máquina onde estiver o Failover “cair”, o que acontece? Será que não volta tudo ao problema original? Isto quer dizer, de nada teria adiantado investir neste conceito, pois a aplicação deixaria de funcionar, mesmo estando os dois servidores de aplicação operacionais… Esta situação pode ocorrer?
Oi Eilton,
É uma boa pergunta, qualquer solução de redundância você terá esse risco, neste caso eu deveria ter uma redundância para o servidor de failover, lembro que aqui estou criando uma redundância para os servidores datasnap.
Como o servidor de failover conecta através de HTTP, você pode aqui ter várias formas de implementar redundância, umas delas através de roteamento direto em caso de queda do servidor Failover.
No final é melhor ter a redundância nos servidores DataSnap e garantir uma boa infraestrutura para suportar o servidor de failover.
Andreano, parei no tempo no Delphi (2007), mas pelo que me lembro do DataSnap, o balanceamento de carga era meio tosco: era implementado através de um sorteio em uma lista de app. servers. Para fazer um balanceamento de cargas mais eficiente, eu tinha que criar um serviço para monitorar os app. servers , conseguindo assim priorizar a carga dos servers mais ociosos, ao invés de um simples sorteio. Isso mudou na nova versão ou continua do mesmo jeito?
Christiano, no caso de balanceamento de carga você poderá reutilizar essa solução que você criou com o novo DataSnap, pois o redirecionamento é feito de forma muito simples, o que antes era meio complicado.
Nao to conseguindo baixar o codigo do Failover… tem como vereficar?
Olha no diretório Failover, está lá
nao consegui achar o diretorio, o arquivo que baixei foi este 27391_datasnap_2010_samples
Obrigado baixei de volta e consegui.
Andreano gostaria de agradecer por disponibilizar os materiais, já me ajudou bastante. Só tive um problema para conectar ao arquivo DSSERVERLOG.IB disponibilizado com os exemplos. Ocorre um erro na conexao (o mesmo nao ocorre ao conectar no employee.IB): unsupported on-disk structure for file XXXXX; found 13; support 12. Acredito que eu esteja usando uma versão antiga do interbase, estou certo? Você poderia disponibilizar o script de criação desse bd? Dessa forma que eu poderia criar 0 bd aqui e rodar sua aplicação exemplo sem erros. Muito obrigado. Abraço
Oi Leandro,
Fico contente em saber que os exemplos estão ajudando. Sobre o erro é porque eu criei esse banco com IB 2009, faz o seguinte, deleta este arquivo, o servidor irá criá-lo de novo.
Bom dia Andreano!
Estou aqui para parabenizálo, por este interessante artigo!
Gostaria de saber como faço para implementar o LoadBalance, procurei mas não achei.
Você saberia me informar aonde encontro vídeo-aulas ou algum site que ensine como fazer?
Agradeço a atenção,
Larissa.
Oi Larissa,
Obrigado por acessar o meu blog.
O vídeo está no post, por alguma razão ele sumiu mas agora está de volta. Além disso o código fonte do exemplo está disponível no link ao final do post. Com esse material você poderá reusar ou montar o seu próprio servidor Failover.
Oi Andreano,
Você poderia dar uma explicação detalhada de como o Delphi 2010 faz o balanceamento de carga? Quais critérios são adotados na hora de decidir qual o melhor servidor a aplicação cliente deve conectar? É analisado sobrecarga de CPU, memória, HD, número de conexões…
Obrigado.
Marcelo,
O controle de como fazer o balanceamento depende da sua implementação, no exemplo que mostrei eu redireciono a conexão quando um erro acontece na comunicação.
O mesmo irá se aplicar a balanceamento de carga, você descobrindo o nível de utilização de cada servidor irá decidir para onde enviar a conexão. O nível de utilização pode ser baseado nos critérios que você mencionou, mas geralmente se utiliza CPU e memória.
Oi Andreano,
Usar uma conexão HTTP não seria mais lento do que uma conexão TCP/IP ao servidor Failover? Porque o Delphi 2010 optou por uma solução HTTP de Failover e não por uma solução TCP/IP de forma mais simples?
Obrigado.
Oi Marcelo,
HTTP é uma camada que corre sobre TCP/IP, isso o torno um pouco mais lento do que puro TCP. No exemplo que disponibilizei veja que a conexão do servidor de Failover para o servidor DataSnap é feita através de TCP/IP. Usamos HTTP como solução, pois todo o gerenciamento de sessão já está implementado no protocolo, facilita o roteamento das sessões, liberação de porta em firewall, etc… Lembre-se que nossa conexão DataSnap através de HTTP é bem leve e tem uma ótima performance.
Ola Andreano.
Estou começando a implementar o Failover em minha aplicação. Porém, estou me dando o seguinte erro : “Protocol http can be used after an adequate instance of TDBXCommunicationLayer is registered with TDBXCommunicationLayerFactory.” quando estou dando um connect := true.
Eu apenas arrastei a conexao do DataExplorer. Falta mais alguma coisa ???
Obrigado.
Oi Diego,
A comunicação do cliente tem que usar HTTP, verifica no seu SQLConnection se assim está.
o SQLConnection esta da seguinte forma:
;DelegateConnection=DBXTraceConnection
drivername=DataSnap
HostName=pc140
Port=8080
CommunicationProtocol=http
OBS: qdo da um active pelo compomente, ele conecta normal, em tempo de projeto, porem em tempo de execução ele apresenta o erro postado anterior.
Andreano, consegui fazer funcionar, estava faltando a declaração de uma unit. Agora uma dúvida, o servidor Failover fica em cada maquina cliente, ou na mesma maquina servidor datasnap ?
Olá Andreado, no DataSnap existe uma forma de conectarmos a um servidor datasnap através de roteador? ou seja, sem especificar o IP da conexão?
alguma coisa que capturassemos as informações de conexão com o Host.
Muito parecido como esse programas de acesso remoto faz, como o teamviewer, logmein, EchoVNC etc.
Gostaria de saber se você tem algum exemplo de failover para TCP-IP?
@Glayson para fazer failover a conexão tem que ser HTTP no DataSnap, neste exemplo uso TCP do DataSnap Server para o banco de dados
Andreano, boa tarde !
O exemplo funcionou corretamente mas não consigo voltar a utilizar o servidor 211. Ou seja, Ativei os dois (211 2 213) depois desativei o 211 e redirecionou para o 213 corretamente.
Depois reativei o 211 e desativei o 213 ai o redirecionamento não volta mais. Você poderia me dá uma dica sobre isso ?
Obrigado !
Andreano, boa tarde !
Primeiramente, parabéns pelo artigo.. Me ajudou muito..
Mas uma dúvida ainda continua, ao voltar o servidor da porta 211 e desativar o servidor 213 o programa não fez a alteração 213 -> 211 somente 211-213.. O que pode estar ocorrendo.
Desde já agradeço.
Abraços!
@Luiz, a implementação foi feita como exemplo para mudar de 211 para 213 apenas.
A idéia é que vocês peguem o código agora e façam as implementações necessárias para o seu ambiente.
Andreano, peguei seu exemplo e testei no XE2, funcionou exatamente como voce postou, obrigado pela dica. O unico problem que eu encontrei é que se eu chamar o metodo via browse:
http://localhost:8080/datasnap/rest/TServerMethods1/EchoString/testando
ele direciona sempre para a porta 211, se eu parar o servidor da 211 e executar novamente pelo browse, da a seguinte mensagem:
{“error”:”Socket Error # 10061\r\nConnection refused.”}
,ou seja, da a impressao que o Failover neste caso sempre joga para o 212. Estou criando uma aplicação totalmente web e estou com esse problema. Voce tem alguma dica sobre isso? Obrigado
Como usar o exemplo no XE6? Não estou conseguindo. Podem me ajudar?
Andreano,
Este exemplo seu ainda é válido para o XE6?
Pensei numa bobeira, poderia o servidor de Failover ficar na própria maquina da aplicação?
[]s
Nilson,
Não testei em XE6, se você quiser testar fique a vontade 🙂
Não seria recomendado o Failover ficar na mesma máquina da aplicação
Andreanno,
Neste exemplo parece que se a porta 211 cair, direciona para a 213 sempre, no caso de se ter N servidores como seria?
Exemplo se o 211 e o 213 cair e eu quisesse direcionar para um terceiro ou um quarto?
Olá, pessoal.
Adriano, quero te agradecer por vc ter compartilhado esse seu conhecimento que foi muito bom para uma grande resolução de problemas que temos. Muito boa a sua iniciativa.
Bom, vou compartilhar um pouco do que entendi com o exemplo do Adriano.
Pessoal, pelo que entendi, cada conexão que é bem sucedida, é gerado uma espécie de índice, ou seja um contador. Então no momento que é gerado o erro, ele verifica o contador ou seja, e pula para a segunda ou primeira tentativa, como vc preferiria , armazenando o contador para uma próxima conexão. Então eu pensei, pq não verificar em qual índice se encontra a seção e toma uma decisão. Pq por exemplo, se já estiver em sua última opção de conexão, vc pode voltar para a primeira conexão já que foi identificado que é a última opção..
Bom pessoal, tenho o conhecimento ainda bem limitado quando o assunto é DatSnap, mas aqui em meu projeto, está funcionando perfeitamente.
Obrigado mais uma vez, Adriano Lanusse.
Alguém teria um descrição melhor do que exatamente faz a função LogBytes e porque só é chamada quando for o servidor original (userFlag = 1)?