Tag Archives: Blpop

Como utilizar blpop de Redis como sincronizador de tareas en un entorno distribuido

Hace poco tuve que desarrollar un sistema de cálculo de probabilidades de forma distribuida, de manera que tenía múltiples procesos que estaban esperando inputs para calcular las probabilidades de una parte del dataset total. Cada uno de estos procesos podía realizar sus operaciones independientemente de los otros procesos, pero como es de esperar, era importante que dado un input cualquiera:

  • Lo calculara el primer proceso que estuviera disponible.
  • Solo lo ejecutara un proceso.

La carga a mi sistema llegaba de una forma irregular e impredecible, ya que depende de qué y cuándo quieren hacer algo los usuarios, por lo que los procesos de cálculo tenía que ejecutarlos en modo daemon para que estuvieran siempre escuchando, atentos a cuando llegara el trabajo.

En este punto, en la sincronización de la lectura de los inputs a procesar, es cuando decidí utilizar Redis, y más concretamente la operación blpop (Blocking List Pop).

Redis es una base de datos NoSql cuyas principales características son:

  • Está en memoria.
  • Es key – value.
  • Permite trabajar con un conjunto limitado de tipos de datos (strings, hashes, lists, sets y alguno más).

Y la operación blpop lo que hace es bloquear el cliente que está intentando leer de la lista hasta que hay por lo menos un elemento para recuperar, pudiendo establecer si se quiere un timeout, o dejar esperando “para siempre”.

Con esto, los actores que generan el input que debe ser calculado estadísticamente, acaban insertando en la cola, llamémosla INPUT_TASKS, mediante operaciones RPUSH, es decir, insertando por la derecha (al final de la lista). Por otra parte tenemos N daemons ejecutándose y bloqueados, a la espera de que entren tareas en INPUT_TASKS, y respetando un “orden en la cola” por estricto orden de llegada. Conforme va habiendo tareas en el INPUT_TASKS los daemons van cogiéndolas y procesándolas. Si la lista de tareas es más larga que la capacidad de los daemons, los elementos permanecerán en INPUT_TASKS hasta que los procesos de cálculo vayan terminando y vuelvan a la cola a recuperar la siguiente tarea. De esta forma se van consumiendo todas las tareas hasta que se vacía INPUT_TASKS, y de nuevo los daemons se quedan esperando nuevos inputs de forma bloqueante.