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:

  1. Execute o servidor Failover, o exemplo utiliza HTTP e porta 8080
  2. 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
  3. Crie um DataSnap alias no Data Explorer, lembre-se de utilizar o protocolo HTTP e porta 8080
  4. 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)
  5. Feche a aplicação DataSnap server, porta 211
  6. Repita o passo número 4 e veja que o retorno será Delphi 2010 (Server 213)
  7. 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

38 respostas
  1. Elton
    Elton says:

    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?

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      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.

      Responder
  2. Christiano Coutinho
    Christiano Coutinho says:

    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?

    Responder
  3. Andreano Lanusse
    Andreano Lanusse says:

    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.

    Responder
  4. leandro
    leandro says:

    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

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      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.

      Responder
  5. Larissa Franco
    Larissa Franco says:

    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.

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      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.

      Responder
  6. Marcelo
    Marcelo says:

    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.

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      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.

      Responder
  7. Marcelo
    Marcelo says:

    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.

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      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.

      Responder
  8. Diego
    Diego says:

    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.

    Responder
  9. Diego
    Diego says:

    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.

    Responder
  10. Diego
    Diego says:

    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 ?

    Responder
  11. Rodrigo Rodrigues
    Rodrigo Rodrigues says:

    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.

    Responder
  12. Luiz Fernado Campos Bhering
    Luiz Fernado Campos Bhering says:

    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 !

    Responder
  13. Luiz Fernado Campos Bhering
    Luiz Fernado Campos Bhering says:

    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!

    Responder
    • Andreano Lanusse
      Andreano Lanusse says:

      @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.

      Responder
      • Tadeu
        Tadeu says:

        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

        Responder
  14. Nilson Chagas
    Nilson Chagas says:

    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

    Responder
  15. Vinicius
    Vinicius says:

    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?

    Responder
    • Kleber Assis
      Kleber Assis says:

      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.

      Responder
  16. Lucas Steffen
    Lucas Steffen says:

    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)?

    Responder

Trackbacks & Pingbacks

  1. […] ler o artigo na integra acesse o blog do Andreano. Abaixo você confere o vídeo sobre o mesmo […]

  2. […] This post was mentioned on Twitter by Andreano Lanusse, Ramos da Informática. Ramos da Informática said: RT @andreanolanusse: Blog post: Como implementar Failover e Load Balance no DataSnap 2010 http://bit.ly/7tpt2m #Delphi #DataSnap […]

Deixe uma resposta

Want to join the discussion?
Feel free to contribute!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *


Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.