Comment pouvez-vous faire en sorte qu'une grappe n'exécute une tâche qu'une seule fois?

13

Si vous aviez une tâche que vous ne vouliez exécuter qu'une seule fois sur un cluster de serveurs, à intervalles réguliers quelle serait la meilleure façon d'y parvenir? La définition de cluster dans ce cas est de 2 serveurs identiques ou plus avec des sessions distribuées situées derrière un équilibreur de charge.

Cas d'utilisation: vous avez une tâche coûteuse à exécuter qui ne doit être exécutée qu'une fois toutes les X heures. Ce travail pourrait par exemple parcourir un tas d'enregistrements et mettre à jour leur statut.

  • Le pire scénario est que l'exécution du travail à deux reprises invalide vos données.
  • Dans le meilleur des cas, le travail utilise des ressources sur tous vos serveurs.

Résumé des exigences:

  1. Le travail doit toujours s'exécuter même si l'un des nœuds est en panne.
  2. Le travail ne doit être exécuté qu'une seule fois par planification.
  3. Si plusieurs travaux sont planifiés en même temps ou à des heures qui se chevauchent, le nombre de travaux en cours d'exécution est réparti également entre les serveurs.
  4. Les machines doivent avoir la même base de code et être synchronisées via NTP.
  5. La configuration peut différer d'un nœud à l'autre, selon les variables d'environnement.
  6. Le travail doit commencer à l'heure ou dans un intervalle donné de l'heure assignée. (disons 5 minutes par exemple)

Solutions possibles

  • Définissez un nœud comme nœud maître, cela ne fonctionne pas car il viole 1 ci-dessus.
  • Demandez à l'équilibreur de charge d'équilibrer le démarrage du travail. Malheureusement, cela a pour effet secondaire que si plusieurs tâches s'exécutent en même temps, elles peuvent toutes être exécutées par la même machine.

Cela devrait s'exécuter en Java, dans un conteneur de servlet. Cependant, il ne code pas les emplois que je recherche.

C'est sûrement un problème résolu avec la meilleure solution connue.


Question connexe. /programming/5949038/schedule-job-executes-twice-on-cluster

Ce n'est pas un doublon car la solution est insuffisante selon ces 5 exigences données ci-dessus. La solution la plus votée souffre d'un problème de race et la deuxième solution viole l'exigence 3

Nous s
la source

Réponses:

16

Avez-vous une base de données partagée? J'ai fait cela en utilisant une base de données comme arbitre dans le passé.

Fondamentalement, chaque "travail" est représenté sous forme de ligne dans la base de données. Vous planifiez un travail en ajoutant une ligne à la base de données avec l'heure à laquelle vous souhaitez qu'elle s'exécute, puis chaque serveur:

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

De cette façon, ils choisiront tous le travail qui doit s'exécuter ensuite . Ils dorment tous pour se réveiller lorsque le travail est censé s'exécuter. Ensuite, ils font tous ceci:

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

:idest l'identifiant de l'emploi que vous avez obtenu à l'étape ci-dessus. Étant donné que la mise à jour est atomique, un seul des serveurs mettra réellement à jour la ligne, vous pouvez vérifier le code d'état "nombre de mises à jour de lignes" de la base de données pour déterminer si vous étiez le serveur qui a réellement mis à jour la ligne, et donc si vous êtes le serveur qui arrive à exécuter le travail.

Si vous n'avez pas "gagné" et que vous n'exécutez pas le travail, revenez immédiatement à l'étape 1. Si vous avez "gagné", planifiez l'exécution du travail dans un autre thread, puis attendez quelques secondes avant de revenir à l'étape 1. De cette façon, les serveurs qui n'ont pas obtenu le travail cette fois sont plus susceptibles de récupérer un travail qui doit s'exécuter immédiatement.

Dean Harding
la source
1
Quel niveau d'isolement utilisez-vous ici? Lire engagé ou sérialiser?
Maverick Riz
2

Plusieurs serveurs d'applications ont une fonctionnalité pour les «services singleton à l'échelle du cluster».

Par exemple, Weblogic a une fonction de service Singleton qui est configurée via la console d'administration Web.

Vous devez écrire une classe qui implémente weblogic.cluster.singleton.SingletonService et l'utiliser pour déclarer le service dans la console d'administration. Le cluster prend soin d'instancier la classe et de vous avertir lorsque le service est démarré ou arrêté. L'interface SingletonService a une méthode activate () et deactivate ().

Les appels Weblogic activent () lors de la première apparition du service sur l'un des nœuds du cluster. Si le nœud sélectionné tombe en panne, le serveur d'administration "déplace" le service sur un autre serveur, en appelant activate () là-bas.

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

Alfred Faltiska
la source