Como você pode fazer um cluster executar uma tarefa apenas uma vez?

13

Se você tivesse uma tarefa que desejava executar apenas uma vez em um cluster de servidores, a intervalos regulares, qual seria a melhor maneira de conseguir isso? A definição de cluster nesse caso é de 2 ou mais servidores idênticos com sessões distribuídas sentadas atrás de um balanceador de carga.

Caso de uso: você tem uma tarefa que é cara de executar e deve ser executada apenas uma vez a cada X horas. Este trabalho pode, por exemplo, repetir vários registros e atualizar seu status.

  • O pior cenário é que a execução do trabalho duas vezes invalida seus dados.
  • O melhor cenário é que o trabalho utilize recursos em todos os seus servidores.

Resumo dos Requisitos:

  1. O trabalho ainda deve ser executado, mesmo se um dos nós estiver inativo.
  2. O trabalho deve ser executado apenas uma vez por agendamento.
  3. Se vários trabalhos forem agendados ao mesmo tempo ou em sobreposição, o número de trabalhos em execução será distribuído igualmente entre os servidores.
  4. As máquinas devem ter a mesma base de código e ser sincronizadas via NTP.
  5. A configuração pode diferir entre nó e nó, por variáveis ​​de ambiente.
  6. O trabalho deve começar no prazo ou dentro de um determinado intervalo do tempo atribuído. (digamos 5 minutos, por exemplo)

Soluções possíveis

  • Defina um nó como nó principal, isso não funciona, pois viola 1 acima.
  • Faça uma solicitação para que o balanceador de carga seja equilibrado para iniciar o trabalho. Infelizmente, isso tem o efeito colateral de que, se você tiver vários trabalhos em execução ao mesmo tempo, todos eles possam ser executados na mesma máquina.

Isso teria que ser executado em Java, em um contêiner de servlet. No entanto, não está codificando os trabalhos que estou procurando.

Certamente este é um problema resolvido com a melhor solução conhecida.


Pergunta relacionada. /programming/5949038/schedule-job-executes-twice-on-cluster

Isso não é duplicado, pois a solução é insuficiente conforme os 5 requisitos fornecidos acima. A solução mais votada sofre de um problema de corrida e a segunda solução viola o requisito 3

Wes
fonte

Respostas:

16

Você tem um banco de dados compartilhado? Eu fiz isso usando um banco de dados como árbitro no passado.

Basicamente, cada "trabalho" é representado como uma linha no banco de dados. Você agende um trabalho adicionando uma linha ao banco de dados com o tempo que deseja que ele seja executado e cada servidor:

SELECT TOP 1 *
FROM jobs
WHERE state = 'NotRun'
ORDER BY run_time ASC

Dessa forma, todos escolherão o trabalho que está programado para ser executado em seguida . Todos dormem para acordar quando o trabalho deve ser executado. Então, todos eles fazem isso:

UPDATE jobs
SET state = 'Running'
WHERE job_id = :id
  AND state = 'NotRun'

Onde :idestá o identificador do trabalho que você obteve na etapa acima. Como a atualização é atômica, apenas um dos servidores atualiza a linha, você pode verificar o código de status "número de atualizações de linhas" do banco de dados para determinar se você foi o servidor que realmente atualizou a linha e, portanto, se você é o servidor que consegue executar o trabalho.

Se você não "venceu" e não está executando o trabalho, volte para a etapa 1 imediatamente. Se você "venceu", programe a tarefa para ser executada em outro encadeamento e aguarde alguns segundos antes de voltar para a etapa 1. Dessa forma, os servidores que não obtiveram a tarefa dessa vez têm mais probabilidade de escolher uma tarefa que está programado para ser executado imediatamente.

Dean Harding
fonte
1
Qual nível de isloation você está usando aqui? Leia confirmado ou serializado?
Maverick Riz
2

Vários servidores de aplicativos têm um recurso para "serviços singleton em todo o cluster".

Por exemplo, o Weblogic possui um recurso de Serviço Singleton configurado através do console de administração da web.

Você precisa escrever uma classe que implemente weblogic.cluster.singleton.SingletonService e usá-la para declarar o serviço no console administrativo. O cluster cuida de instanciar a classe e notificá-lo quando o serviço for iniciado ou parado. A interface SingletonService possui um método enable () e deactivate ().

As chamadas da Weblogic são ativadas () quando ele abre o serviço pela primeira vez em um dos nós do cluster. Se o nó selecionado ficar inativo, o servidor administrador "moverá" o serviço em um servidor diferente, chamando de ativar () lá.

http://docs.oracle.com/cd/E12839_01/apirefs.1111/e13952/taskhelp/clusters/ConfigureSingletonService.html

Alfred Faltiska
fonte