Celery: [K8S] livenessProbe y readinessProbe para apio y trabajadores

Creado en 8 jun. 2017  ·  31Comentarios  ·  Fuente: celery/celery

Hola,

Estoy usando Kubernetes para implementar mi aplicación de Python, Kubernetes proporciona un livenessProbe y readinessProbe, consulte aquí .

¿Cómo puedo hacer para verificar si mi batido de apio o mi albahaca están vivos y en el estado correcto?
El PID no es una solución porque no se puede utilizar para detectar un punto muerto, por ejemplo.

Gracias de antemano por tu ayuda,

Atentamente,

Deployment Question Needs Verification ✘

Comentario más útil

celery inspect ping funciona, pero necesita bash para reemplazar la variable de entorno de esta manera:

        livenessProbe:
          exec:
            # bash is needed to replace the environment variable
            command: [
              "bash",
              "-c",
              "celery inspect ping -A apps -d celery@$HOSTNAME"
            ]
          initialDelaySeconds: 30  # startup takes some time
          periodSeconds: 60  # default is quite often and celery uses a lot cpu/ram then.
          timeoutSeconds: 10  # default is too low

Todos 31 comentarios

El apio tiene una API de monitoreo que puede usar.
Una vaina debe considerarse activa si el trabajador de Apio envía un latido .
Un pod debe considerarse listo si el trabajador ha enviado el evento en línea del

Si tiene problemas específicos o solicitudes de funciones, abra un problema por separado.

¿Funcionaría esto?

readinessProbe:
          exec:
            command:
            - "/bin/sh"
            - "-c"
            - "celery -A path.to.app status | grep -o ': OK'"
          initialDelaySeconds: 30
          periodSeconds: 10

@ 7wonders Primero deberías extraer el nombre del nodo de apio. Esta readinessProbe fallará si falla alguna instancia de apio, que no es lo que desea.

@thedrow Hmm, creo que en realidad tendrá éxito incluso si el nodo real ha fallado, pero otro está bien, lo que tampoco es un gran resultado.

Parece

/bin/sh -c 'exec celery -A path.to.app inspect ping -d celery@$HOSTNAME' es lo suficientemente bueno para la verificación de preparación y verifica solo un nodo.

Tenga en cuenta que en algunas aplicaciones, la ejecución de este comando puede demorar unos segundos con la CPU completa Y los valores predeterminados de kubernetes son ejecutarlo cada 10 segundos.

Por lo tanto, es mucho más seguro tener un períodoSegundos alto (el nuestro está configurado en 300).

@redbaron, ¿

Por alguna razón, esta prueba de preparación no es ni de lejos satisfactoria para nosotros. La inspección responde de forma no determinista sin carga en nuestro clúster. Ejecutamos el formato así:

apio inspeccionar ping -b " redis: // archii-redis-master : 6379" -d apio @ archii-task-crawl-integration-7d96d86b9d-jwtq7

Y con tiempos de ping normales (10 segundos), nuestro clúster es completamente eliminado por la CPU que requiere el apio.

~ Lo uso para vivir con un intervalo de 30 segundos: sh -c celery -A path.to.app status | grep "${HOSTNAME}:.*OK" ~
Utilizo esto para vivir con un intervalo de 30 segundos: sh -c celery -A path.to.app inspect ping --destination celery@${HOSTNAME}
No parece causar ninguna carga adicional, tengo una flota de más de 100 trabajadores.

Las sondas de preparación no son necesarias, el apio nunca se usa en un servicio. Acabo de configurar minReadySeconds: 10 que es lo suficientemente bueno para retrasar el inicio del trabajador en implementaciones continuas, pero obviamente depende del tiempo de inicio de Celery para su proyecto, así que examine los registros y configúrelos en consecuencia.

Las sondas de preparación siguen siendo útiles incluso si no se utilizan en un servicio. Específicamente, cuando realiza una implementación de trabajadores y desea asegurarse de que su implementación fue exitosa, generalmente usa kubectl rollout status deployment . Sin las sondas de preparación, hemos implementado un código incorrecto que no inició el apio y no lo sabía.

Mi solucion fue:

readinessProbe:
  exec:
    command:
      [
        "/usr/local/bin/python",
        "-c",
        "\"import os;from celery.task.control import inspect;from <APP> import celery_app;exit(0 if os.environ['HOSTNAME'] in ','.join(inspect(app=celery_app).stats().keys()) else 1)\""
      ]

Otros parecen no funcionar 🤷‍♂️

¡Gracias @yardensachs!
Dedique mucho tiempo a depurar lo que está mal con otras soluciones, pero de ninguna manera
Parece que el comando celery inspect ping no devuelve exit (0) o algo por el estilo

celery inspect ping funciona, pero necesita bash para reemplazar la variable de entorno de esta manera:

        livenessProbe:
          exec:
            # bash is needed to replace the environment variable
            command: [
              "bash",
              "-c",
              "celery inspect ping -A apps -d celery@$HOSTNAME"
            ]
          initialDelaySeconds: 30  # startup takes some time
          periodSeconds: 60  # default is quite often and celery uses a lot cpu/ram then.
          timeoutSeconds: 10  # default is too low

bueno saber

Terminamos arrancando el ping de inspección de apio de nuestras sondas de vitalidad porque descubrimos que bajo una carga más pesada, el ping se colgaría durante minutos a la vez, aunque los trabajos se estaban procesando bien y no había atrasos. Tengo la sensación de que tuvo algo que ver con el uso de eventlet, pero seguimos investigándolo.

@WillPlatnick Eso no sucederá con 5.0 porque Celery será asíncrono, por lo que habrá capacidad reservada para las corrutinas de control.

Tengo problemas con inspect ping procesos de generación difuntos / zombies:

root      2296  0.0  0.0      0     0 ?        Z    16:04   0:00 [python] <defunct>
root      2323  0.0  0.0      0     0 ?        Z    16:05   0:00 [python] <defunct>
...

¿Alguien más se encuentra con esto? No hay un argumento --pool para forzar la ejecución de un solo proceso.

¿Puedo preguntar qué estás usando en lugar de celery inspect ping @WillPlatnick? Hemos encontrado un problema similar con la sonda fallando bajo una carga pesada.

@mcyprian Nos deshicimos de la sonda de vida. Mi instinto me dice que tiene algo que ver con eventlet, pero no lo hemos convertido en una prioridad para resolverlo.

nos encontramos con el mismo problema de CPU con el corredor de Redis

¿Ha encontrado alguien una solución?
También estábamos experimentando con la programación de "debug_task" en la cola cuyo nombre basamos en el nombre del contenedor. El problema es que ahora tenemos toneladas de colas antiguas en RabbitMQ

Tenga en cuenta que el uso

sh -c celery -A path.to.app status | grep "${HOSTNAME}:.*OK"

como se sugiere en https://github.com/celery/celery/issues/4079#issuecomment -437415370 dará lugar a informes de errores masivos en rabbitmq, consulte https://github.com/celery/celery/issues/4355#issuecomment - 578786369

Creo que he encontrado una manera de reducir el uso de CPU de inspeccionar ping.

celery -b amqp: // usuario: pass @ rabbitmq : 5672 / vhost inspecciona ping

No cargar las configuraciones de apio usando -A path.to.celery ciertamente ayudó con el uso de la CPU,
alguien podría verificar.

Creo que he encontrado una manera de reducir el uso de CPU de inspeccionar ping.

celery -b amqp: // usuario: pass @ rabbitmq : 5672 / vhost inspecciona ping

No cargar las configuraciones de apio usando -A path.to.celery ciertamente ayudó con el uso de la CPU,
alguien podría verificar.

¡Lindo! Es mucho mejor que con la aplicación cargada.
Pero todavía tenemos la enorme sobrecarga de un proceso de Python que comienza + importación de apio. Todavía recomendaría un período alto.

Hola,
celery inspeccionar ping -A app.tasks -d celery @ $ HOSTNAME me da "Error: Transmisión no admitida por transporte 'sqs'".
Estoy usando SQS como intermediario, por lo que esto significa que el comando 'inspeccionar' / 'estado' no funcionará con SQS.

Hemos descubierto que, a escala, todas las funciones de control remoto están provocando que la instancia de Redis aumente en la CPU debido a la configuración de comandos en la tecla kombu.pidbox , por lo que no podemos usar ping, estado o inspeccionar como están. todos usando control remoto e intentando deshabilitar el control remoto para el caso de uso de producción.

Me parece que tener una cola de verificación de estado dedicada es la manera correcta, pero no estoy seguro en absoluto

¿Alguien tiene alguna otra dirección que no involucre el control remoto para probar los controles de salud?

Usamos colas de verificación de estado dedicadas con políticas de desalojo de RabbitMQ (las colas se eliminan automáticamente) con éxito durante algún tiempo, y estamos contentos con la solución. Sobre todo porque esta comprobación es, de hecho, comprobar que el trabajador procesa la tarea y finaliza. Desde que lo presentamos, no tuvimos más problemas con los trabajadores atascados.

@bartoszhernas, ¿te importaría compartir un código para eso? ¿los pone en cola a través de beat y luego los trabajadores lo recogen?

Me encantaría ver el código + la sección de prueba de vida.

Hola, el código es realmente fácil:

En Kubernetes, especifico el nombre de la cola en función de POD_NAME y lo paso al script livecheck:

        livenessProbe:
          initialDelaySeconds: 120
          periodSeconds: 70
          failureThreshold: 1
          exec:
            command:
            - bash 
            - "-c" 
            - |
              python celery_liveness_probe.py $LIVENESS_QUEUE_NAME
        env:
        - name: MY_POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name

        - name: LIVENESS_QUEUE_NAME
          value: queue-$(MY_POD_NAME)

(debe usar bash -c, porque Kubernetes no expande los ENV cuando intenta pasarlo como comando directamente)

entonces celery_liveness_probe.py solo está configurando Django para poder usar Celery y programar la tarea en la cola de POD

# encoding: utf-8
from __future__ import absolute_import, unicode_literals

import os
import sys

if __name__ == "__main__":
    import django

    sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ahoy.archive.settings")
    django.setup()
    from ahoy.archive.apps.eventbus.service import eventbus_service

    exit(0 if eventbus_service.health_check(sys.argv[1] if sys.argv and len(sys.argv) > 1 else None) else 1)

la función de verificación de estado envía la tarea y espera los resultados

    def health_check(self, queue_name: Optional[str] = None) -> bool:
        event = self.celery.send_task(
            AhoyEventBusTaskName.LIVENESS_PROBE,
            None,
            queue=queue_name or self.origin_queue,
            ignore_result=False,
            acks_late=True,
            retry=False,
            priority=255
        )

        try:
            is_success = event.get(timeout=10)
        except (celery.exceptions.TimeoutError, AttributeError):
            is_success = False

        return is_success

Básicamente: envíe una tarea y, si devuelve resultados, el trabajador está sano. Si el trabajador se atascó (sucedió muchas veces), las tareas nunca terminan, el Pod se reinicia y todo vuelve a la normalidad.

La única advertencia es que debe lidiar con las colas antiguas, con RabbitMQ es fácil, solo configuramos una política de vencimiento en la cola
https://www.rabbitmq.com/ttl.html#queue -ttl

@bartoszhernas ¡ gracias por compartir el código!

como dijiste, mis colas son dinámicas y estamos usando Redis, por lo que realmente necesitamos encontrar una manera de lidiar con el vencimiento de los nombres de las colas en Redis.

Sí, tenemos un problema similar con BullMQ con Redis. Mi idea es escribir CronJob para Kubernetes que borre las colas cada cierto tiempo.

¿Fue útil esta página
0 / 5 - 0 calificaciones