¿Cómo puede hacer que un clúster ejecute una tarea solo una vez?

13

Si tuviera una tarea que quisiera ejecutar solo una vez en un grupo de servidores, a intervalos regulares, ¿cuál sería la mejor manera de lograrlo? La definición de clúster en este caso es 2 o más servidores idénticos con sesiones distribuidas ubicadas detrás de un equilibrador de carga.

Caso de uso: tiene una tarea costosa de ejecutar que solo debe ejecutarse una vez por X horas. Este trabajo podría, por ejemplo, iterar sobre un montón de registros y actualizar su estado.

  • El peor de los casos es que tener el trabajo ejecutado dos veces invalida sus datos.
  • El mejor de los casos es que el trabajo utiliza recursos en todos sus servidores.

Resumen de requisitos:

  1. El trabajo aún debe ejecutarse incluso si uno de los nodos está inactivo.
  2. El trabajo solo debe ejecutarse una vez por programa.
  3. Si se programan varios trabajos al mismo tiempo o en momentos superpuestos, el número de trabajos en ejecución se distribuye equitativamente entre los servidores.
  4. Las máquinas deben tener la misma base de código y estar sincronizadas a través de NTP.
  5. La configuración puede diferir entre nodo y nodo, según las variables de entorno.
  6. El trabajo debe comenzar a tiempo o dentro de un intervalo dado del tiempo asignado. (por ejemplo, 5 minutos)

Soluciones posibles

  • Establezca un nodo como el nodo maestro, esto no funciona ya que viola 1 anterior.
  • Solicite que el equilibrador de carga se equilibre para iniciar el trabajo. Desafortunadamente, esto tiene el efecto secundario de que si tiene varios trabajos ejecutándose al mismo tiempo, todos pueden ejecutarse en la misma máquina.

Esto debería ejecutarse en Java, en un contenedor de servlet. Sin embargo, no está codificando los trabajos que estoy buscando.

Seguramente este es un problema resuelto con la mejor solución conocida.


Pregunta relacionada /programming/5949038/schedule-job-executes-twice-on-cluster

Esto no es un duplicado ya que la solución es insuficiente según los 5 requisitos dados anteriormente. La solución más votada sufre de un problema racial, y la segunda solución viola el requisito 3

Wes
fuente

Respuestas:

16

¿Tienes una base de datos compartida? Lo hice usando una base de datos como árbitro en el pasado.

Básicamente, cada "trabajo" se representa como una fila en la base de datos. Usted programa un trabajo agregando una fila a la base de datos con el tiempo que desea que se ejecute y luego cada servidor:

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

De esa manera, todos elegirán el trabajo que está programado para ejecutarse a continuación . Todos duermen para despertarse cuando se supone que el trabajo realmente debe ejecutarse. Entonces, todos hacen esto:

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

¿Dónde :idestá el identificador del trabajo que obtuvo en el paso anterior? Debido a que la actualización es atómica, solo uno de los servidores realmente actualizará la fila, puede verificar el código de estado de "número de actualizaciones de filas" de la base de datos para determinar si usted fue el servidor que realmente actualizó la fila y, por lo tanto, si usted es el servidor eso lleva a ejecutar el trabajo.

Si no "ganó" y no está ejecutando el trabajo, simplemente regrese al paso 1 inmediatamente. Si "ganó", programe el trabajo para que se ejecute en otro subproceso, luego espere un par de segundos antes de volver al paso 1. De esa manera, los servidores que no obtuvieron el trabajo esta vez tienen más probabilidades de elegir un trabajo eso está programado para ejecutarse de inmediato.

Dean Harding
fuente
1
¿Qué nivel de ubicación estás usando aquí? Leer comprometido o serializar?
Maverick Riz
2

Varios servidores de aplicaciones tienen una función para "servicios singleton de clúster".

Por ejemplo, Weblogic tiene una función de Servicio Singleton que se configura a través de la consola de administración web.

Debe escribir una clase que implemente weblogic.cluster.singleton.SingletonService y usarla para declarar el servicio en la consola de administración. El clúster se encarga de crear instancias de la clase y notificarle cuando se inicia o detiene el servicio. La interfaz SingletonService tiene un método enable () y un método deactivate ().

Las llamadas de Weblogic activan () cuando por primera vez abre el servicio en uno de los nodos del clúster. Si el nodo seleccionado se cae, el servidor de administración "mueve" el servicio en un servidor diferente, llamando a activar () allí.

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

Alfred Faltiska
fuente