Pergunta

Eu sei disso com Network Load Balancing e Failover Clusteringpodemos fazer Serviços passivos altamente disponível. Mas que tal Aplicativos ativos?

Exemplo: um dos meus aplicativos recupera algum conteúdo de um recurso externo em um intervalo fixo. Eu imaginei os seguintes cenários:

  1. Execute -o em uma única máquina. Problema: se esta instância cair, o conteúdo não será recuperado
  2. Execute -o em cada máquina do cluster. Problema: o conteúdo será recuperado várias vezes
  3. Tenha -o em cada máquina do cluster, mas execute -o apenas em um deles. Cada instância terá que verificar algum tipo de recurso comum para decidir se é a sua vez realizar a tarefa ou não.

Quando eu estava pensando na solução nº 3, me perguntei qual deveria ser o recurso comum. Pensei em criar uma tabela no banco de dados, onde poderíamos usá -lo para obter um bloqueio global.

Esta é a melhor solução? Como as pessoas geralmente fazem isso?

A propósito, é um aplicativo C# .NET WCF em execução no Windows Server 2008

Foi útil?

Solução

Para tais problemas, eles inventaram filas de mensagens. Imagine o caso quando seus aplicativos em cluster ouvem uma fila de mensagens (se agruparam :-)). Em algum momento, uma instância recebe seu comando inicial para baixar seu recurso externo. Se for bem -sucedido, sua instância libera a mensagem e, em vez disso, publica outra para um tempo de execução posterior que seja igual ao 'tempo de execução' + 'intervalo'. Mas, caso o exemplo morra durante o processamento, isso não é um problema. A mensagem é revertida na fila (após o tempo limite) e alguma outra instância pode buscá -la. Um pouco de transações, um pouco de filas de mensagem

Estou do lado Java Ee do mundo, para que possa ajudá -lo com detalhes de codificação

Outras dicas

Uma vez implementei algo semelhante usando sua solução nº 3.

Crie uma tabela chamada algo como resource_lock, com uma coluna (por exemplo locking_key) que conterá uma chave de travamento.

Então, a cada intervalo, todas as instâncias do seu aplicativo serão:

  1. Execute uma consulta como 'update resource_lock set resource_key = 1 where resource_key is null'. (você também pode inserir um ID específico do servidor, um registro de data e hora, etc.)
  2. Se 0 linhas atualizadas: não faça nada - outra instância do aplicativo já está buscando o recurso.
  3. Se 1 linha atualizada: busque o recurso e defina locking_key de volta a null.

Existem duas vantagens com isso:

  • Se um de seus servidores falhar, o recurso ainda será buscado pelos servidores que ainda estão em execução.
  • Você deixa o bloqueio no banco de dados, isso evita que você mesmo o implemente.

Existem alguns requisitos que você provavelmente conhece, mas não foi descrito na pergunta que torna desafiador uma resposta informada. Algumas dessas perguntas são:

  • A tarefa precisa concluir com sucesso?
  • Se a tarefa não concluir/não concluir com êxito, "quem" precisa saber e que tipo de ação precisa ser executado?
  • Qual é o comportamento se a tarefa não foi concluída quando chegar a hora de executar a tarefa novamente? Deveria correr ou não?
  • Quão importante é que os trabalhos são executados no intervalo especificado? Se o intervalo for a cada 5 minutos, precisa ser a cada 5 minutos ou a tarefa pode ser executada após 5 minutos e 10 segundos?

A primeira etapa é responder como a tarefa periódica estará programada para ser executada. Uma opção é uma tarefa programada para o Windows, mas isso não está inerentemente disponível, mas pode ser possível contornar isso. Se você estiver usando o SQL Server, outra alternativa seria usar o SQL Server Agent como um agendador, pois ele fará o failover como parte do SQL Server.

A próxima etapa para determinar é como invocar o aplicativo WCF. A opção mais fácil seria desencadear um trabalho para invocar o serviço WCF por meio de um endereço IP da NLB. Isso pode ser considerado um não-não se o servidor de banco de dados (ou outro servidor nessa zona) estiver ligando para a zona de aplicativo (é claro que sempre existem exceções como o MSDTC).

Outra opção seria usar o modelo de fila. Esta seria a mais confiável na maioria das situações. Por exemplo, o agente do SQL Server pode executar um procedimento armazenado para inserir um registro em uma tabela de filas. Em cada servidor de aplicativos, uma pesquisa pode pesquisar um registro na fila para processar. O acesso ao registro na fila seria serializado pelo banco de dados para que o primeiro servidor em executar o trabalho (e esse trabalho só funcionaria uma vez).

Dependendo das respostas para as perguntas de abertura nesta resposta, você pode precisar adicionar mais um pouco de manuseio de erros. Se a recuperação do recurso externo geralmente for bastante curto, você pode simplesmente manter o registro da fila bloqueado com um select for update e quando a tarefa é concluída, atualize o status (ou exclua o registro, se desejar). Isso bloqueará outras instâncias de serviço de processar o registro enquanto ele estiver sendo processado em outro servidor e, se ocorrer uma falha durante o processamento da transação, deverá ser revertida e outro serviço no cluster pode pegar o registro. (Embora você possa aumentar o tempo limite da transação até que você pense que precisa.)

Se manter um bloqueio de banco de dados por um longo tempo não for viável, você poderá alterar a lógica e adicionar algum monitoramento aos serviços. Agora, quando um trabalho é iniciado, seu status seria alterado da fila para a execução e o servidor que está processando o registro seria atualizado no registro. Algum tipo de tabela de status de serviço poderia ser criado e cada instância de serviço atualizaria a hora atual toda vez que eles pesquisariam. Isso permitiria que outros serviços do cluster reprocisassem os trabalhos que mostram como execução, mas o serviço em que eles deveriam estar sendo executados não foi "verificado" dentro de um determinado período.

Essa abordagem também tem limitações: e se a tarefa realmente concluísse, mas de alguma forma a conectividade do banco de dados foi perdida - o trabalho poderia ser executado novamente. Obviamente, não acho que o problema de ter ações de banco de dados atômico combinadas com outros recursos não transacionais (por exemplo, solicitação da Web, sistema de arquivos) serão resolvidos facilmente. Suponho que você esteja escrevendo um arquivo ou algo assim - se o conteúdo externo também for colocado em um banco de dados, uma única transação garantirá que tudo seja consistente.

Do ponto de vista da simplicidade, a maneira mais rápida/mais fácil de realizar o que você está procurando seria 'robinar o seu cluster para que, para cada solicitação, uma máquina seja selecionada (por um serviço de gerenciamento de cluster ou algo assim) Para processar uma solicitação. As solicitações reais do cliente não vão diretamente para a máquina que a manipula; Em vez disso, apontam para um único terminal, que atua como proxy para distribuir solicitações de entrada para máquinas com base na disponibilidade e carga. Para citar o link abaixo-referenciado,

O balanceamento de carga da rede é uma maneira de configurar um pool de máquinas, para que eles se revezem em resposta a solicitações. É mais comumente visto em fazendas de servidores: máquinas configuradas de forma idêntica que espalham a carga para um site ou talvez um fazendeiro de servidor de terminal. Você também pode usá -lo para uma fazenda de firewall (ISA), pontos de acesso VPN, na verdade, sempre que você tem tráfego TCP/IP que se tornou muito carga para uma única máquina, mas você ainda deseja que ela apareça como uma única máquina para fins de acesso.

Quanto ao seu aplicativo estar "ativo", esse requisito não considera essa equação, pois se 'ativo' ou 'passivo', o aplicativo ainda faz uma solicitação aos seus servidores.

Existem balanceadores de carga comerciais para atender solicitações no estilo HTTP, de modo que valem a pena investigar, mas com os recursos de balanceamento de carga do W2K8, você pode ser melhor servido batendo neles.

Para mais informações sobre como configurar isso em Win2K8, consulte isto artigo.

Este artigo é muito mais técnico e se concentra no uso do NLB com o Exchange, mas os princípios ainda devem se aplicar à sua situação.

Veja aqui Para outra apresentação detalhada da configuração e configuração do NLB.

Falha nisso, você pode ser bem servido pesquisando / postando no ServerFault, pois o código do seu aplicativo não é (e não deve estar) estritamente ciente de que o NLB existe.

Editar: Adicionado outro link.

Editar (o 2º): o OP corrigiu minha conclusão errônea no conceito 'ativo' vs. 'passivo'. Minha resposta para isso é muito semelhante à minha resposta original, exceto que o serviço 'ativo' (que, como você está usando o WCF, pode ser facilmente um serviço do Windows) pode ser dividido em duas partes: a parte real de processamento e o parte de gerenciamento. A parte de gerenciamento seria executada em um único servidor e atuaria como um balanceador de carga redondo-robin para os outros servidores que fazem o processamento real. É um pouco mais complicado do que o cenário original, mas acredito que proporcionaria uma grande flexibilidade, além de oferecer uma separação limpa entre sua lógica de processamento e gerenciamento.

Em alguns casos, as pessoas acham útil ter três máquinas fazendo todas as solicitações e, em seguida, comparam os resultados no final, para garantir que o resultado esteja absolutamente correto e nenhuma falha de hardware causou problemas ao processá -lo. É isso que eles fazem, por exemplo, aviões.

Outras vezes, você pode viver com um único resultado ruim e um pequeno tempo de inatividade para mudar para um novo serviço, mas só quer que o próximo seja bom. Nesse caso, a solução número 3 com um monitor de batida cardíaca é uma excelente configuração.

Outras vezes, novamente, as pessoas só precisam ser notificadas com um SMS de que seu serviço está inativo e o aplicativo usará apenas alguns dados obsoletos até que você execute manualmente algum tipo de failover.

No seu caso, eu diria que o último é provavelmente mais útil para você. Como você não pode realmente depender do serviço no outro lado disponível, você ainda precisaria encontrar uma solução para o que fazer nesse caso. Devolver dados obsoletos pode ser o que é bom para você, e pode não ser. Lamento ter que dizer: depende.

O Zookeeper faz um bom caso de uso de bloqueios distribuídos. O Zookeeper possui Nodes Z que são como diretórios com dados.

Até o Curador da Netflix já tem muitas receitas e usam. Como: eleição líder, trava distribuída e muito mais.

Acho que temos o cliente do Zookeeper para C#. Você definitivamente deve tentar essas opções. #Opção3

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top