Celery: [K8S] vivenessProbe et préparationProbe pour céleri battu et ouvrières

Créé le 8 juin 2017  ·  31Commentaires  ·  Source: celery/celery

Salut,

J'utilise Kubernetes pour déployer mon application python, Kubernetes fournit un livenessProbe et un readinessProbe voir ici .

Comment puis-je vérifier si mon céleri battu ou mon céleri est vivant et en bon état?
Le PID n'est pas une solution car il ne peut pas être utilisé pour intercepter un blocage par exemple.

Merci d'avance pour votre aide,

Meilleures salutations,

Deployment Question Needs Verification ✘

Commentaire le plus utile

celery inspect ping fonctionne, mais vous avez besoin de bash pour remplacer la variable d'environnement comme ceci:

        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

Tous les 31 commentaires

Celery a une API de surveillance que vous pouvez utiliser.
Une cosse doit être considérée comme vivante si le céleri envoie un battement de cœur .
Un pod doit être considéré comme prêt si le collaborateur a envoyé l'événement worker-online .

Si vous rencontrez des problèmes spécifiques ou des demandes de fonctionnalités, veuillez ouvrir un autre problème.

Cela fonctionnerait-il?

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

@ 7wonders Vous devez d'abord extraire le nom du nœud de céleri. Ce readinessProbe échouera si une instance de céleri échoue, ce qui n'est pas ce que vous voulez.

@thedrow Hmm, je pense que c'est en fait qu'il réussira même si le nœud réel a échoué, mais un autre est correct, ce qui n'est pas non plus un excellent résultat.

Ressemble à

/bin/sh -c 'exec celery -A path.to.app inspect ping -d celery@$HOSTNAME' est assez bon pour le contrôle de disponibilité et vérifie un seul nœud.

Sachez que dans certaines applications, l'exécution de cette commande peut prendre quelques secondes en utilisant le processeur complet ET les valeurs par défaut de kubernetes sont de l'exécuter toutes les 10 secondes.

Il est donc beaucoup plus sûr d'avoir une période élevée de Secondes (la nôtre est fixée à 300).

@redbaron est-ce que cette commande a fonctionné pour vous? Si cela fonctionne, quels sont les paramètres pour le problème de vivacité et de préparation?

Pour une raison quelconque, cette sonde de préparation est loin d'être satisfaisante pour nous. L'inspection répond de manière non déterministe sans charge sur notre cluster. Nous exécutons le format comme ceci:

céleri inspecter ping -b " redis: // archii-redis-master : 6379" -d céleri @ archii-task-crawl-integration-7d96d86b9d-jwtq7

Et avec des temps de ping normaux (10 secondes), notre cluster est complètement tué par le céleri CPU requis.

~ J'utilise ceci pour la vivacité avec un intervalle de 30 s: sh -c celery -A path.to.app status | grep "${HOSTNAME}:.*OK" ~
J'utilise ceci pour la vivacité avec un intervalle de 30 s: sh -c celery -A path.to.app inspect ping --destination celery@${HOSTNAME}
Ne semble pas causer de charge supplémentaire, je gère une flotte de plus de 100 travailleurs.

Les sondes de préparation ne sont pas nécessaires, le céleri n'est jamais utilisé dans un service. Je viens de définir minReadySeconds: 10 ce qui est assez bon pour retarder le démarrage des travailleurs dans les déploiements en cours, mais cela dépend évidemment de l'heure de démarrage de Celery pour votre projet, alors examinez les journaux et définissez-les en conséquence.

Les sondes de préparation sont toujours utiles même si elles ne sont pas utilisées dans un service. Plus précisément, lorsque vous effectuez un déploiement de nœuds de calcul et que vous souhaitez vous assurer que votre déploiement a réussi, vous utilisez généralement kubectl rollout status deployment . Sans sondes de préparation, nous avons déployé un mauvais code qui n'a pas démarré le céleri et ne le savait pas.

Ma solution était:

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)\""
      ]

D'autres semblent ne pas fonctionner 🤷‍♂️

Merci @yardensachs!
Passez beaucoup de temps à déboguer ce qui ne va pas avec d'autres solutions, mais pas question
On dirait que la commande celery inspect ping ne retourne pas exit (0) ou quelque chose de cette façon

celery inspect ping fonctionne, mais vous avez besoin de bash pour remplacer la variable d'environnement comme ceci:

        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

bon à savoir

Nous avons fini par extraire le céleri inspecter le ping de nos sondes de vivacité car nous avons constaté que sous une charge plus lourde, le ping se bloquait pendant quelques minutes à la fois, même si les travaux se déroulaient correctement et qu'il n'y avait pas d'arriéré. J'ai le sentiment que cela a quelque chose à voir avec l'utilisation d'Eventlet, mais nous continuons à l'examiner.

@WillPlatnick Cela n'arrivera pas avec la version 5.0 car Celery sera asynchrone donc il y aura une capacité réservée pour les coroutines de contrôle.

J'ai des problèmes avec inspect ping engendrant des processus obsolètes / 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>
...

Quelqu'un d'autre rencontre-t-il cela? Il n'y a pas d'argument --pool pour forcer l'exécution d'un seul processus.

Puis-je vous demander ce que vous utilisez au lieu de celery inspect ping @WillPlatnick? Nous avons rencontré un problème similaire avec la sonde échouant sous une forte charge.

@mcyprian Nous nous sommes débarrassés de la sonde de vivacité. Mon instinct me dit que cela a quelque chose à voir avec eventlet, mais nous ne nous sommes pas fait une priorité de le découvrir.

nous rencontrons le même problème de processeur avec le courtier Redis

Est-ce que quelqu'un a trouvé une solution?
Nous avons également expérimenté la planification de "debug_task" sur la file d'attente dont nous avons basé le nom sur le nom du conteneur. Le problème est que nous avons des tonnes d'anciennes files d'attente dans RabbitMQ maintenant

Veuillez noter que l'utilisation

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

comme suggéré sur https://github.com/celery/celery/issues/4079#issuecomment -437415370 entraînera des rapports d'erreur massifs sur rabbitmq, voir https://github.com/celery/celery/issues/4355#issuecomment - 578786369

Je pense avoir trouvé un moyen de réduire l'utilisation du processeur de l'inspection ping.

céleri -b amqp: // utilisateur: pass @ rabbitmq : 5672 / vhost inspecter ping

Ne pas charger les configurations de céleri en utilisant -A path.to.cellery a certainement aidé avec l'utilisation du processeur,
quelqu'un pourrait-il vérifier.

Je pense avoir trouvé un moyen de réduire l'utilisation du processeur de l'inspection ping.

céleri -b amqp: // utilisateur: pass @ rabbitmq : 5672 / vhost inspecter ping

Ne pas charger les configurations de céleri en utilisant -A path.to.cellery a certainement aidé avec l'utilisation du processeur,
quelqu'un pourrait-il vérifier.

Agréable! C'est bien mieux qu'avec l'application chargée.
Mais nous avons toujours l'énorme surcharge d'un processus python commençant + importation de céleri. Je recommanderais toujours une période élevée.

Salut,
celery inspect ping -A app.tasks -d celery @ $ HOSTNAME me donne "Erreur: diffusion non prise en charge par le transport 'sqs'".
J'utilise SQS comme courtier, donc cela signifie que la commande «inspect» / «status» ne fonctionnera pas avec SQS?

Nous avons constaté qu'à grande échelle, toutes les fonctionnalités de contrôle à distance provoquent une augmentation de l'instance Redis dans le processeur en raison de la définition de commandes sur la clé kombu.pidbox , nous ne pouvons donc pas utiliser ping, ni status, ni inspecter tels quels. tout en utilisant la télécommande et en essayant de désactiver la télécommande pour un cas d'utilisation de production.

Il me semble qu'avoir une file d'attente de vérification de l'état dédiée est la bonne façon, mais je ne suis pas sûr du tout

Quelqu'un a-t-il une autre direction n'impliquant pas la télécommande pour tester les contrôles de santé?

Nous utilisons des files d'attente de vérifications de l'état dédiées avec les politiques d'éviction RabbitMQ (les files d'attente sont supprimées automatiquement) avec succès depuis un certain temps maintenant, et nous sommes satisfaits de la solution. Principalement parce que cette vérification vérifie en effet que le travailleur traite la tâche et se termine. Depuis que nous l'avons introduit, nous n'avons plus eu de problèmes avec les travailleurs bloqués.

@bartoszhernas est-il prêt à partager du code pour ça? faites-vous la queue via beat et que les travailleurs le ramassent?

aimerait voir le code + la section sonde de vivacité

Salut, le code est vraiment simple:

Dans Kubernetes, je spécifie le nom de la file d'attente en fonction de POD_NAME et je le transmets au 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)

(vous devez utiliser bash -c, car Kubernetes ne développe pas les ENV en essayant de le passer directement en tant que commande)

puis le celery_liveness_probe.py est juste en train de configurer Django pour pouvoir utiliser Celery et planifier la tâche sur la file d'attente du 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 fonction de vérification de l'état envoie la tâche et attend les résultats

    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

Donc, fondamentalement: envoyez une tâche, et si elle renvoie des résultats, le travailleur est en bonne santé. Si le travailleur est resté bloqué (cela s'est produit souvent), les tâches ne se terminent jamais, le pod est redémarré et tout revient à la normale.

La seule mise en garde est que vous devez gérer les anciennes files d'attente, avec RabbitMQ c'est facile, nous venons de mettre en place une politique d'expiration sur la file d'attente
https://www.rabbitmq.com/ttl.html#queue -ttl

@bartoszhernas merci d'avoir partagé le code!

comme vous l'avez dit, mes files d'attente sont dynamiques et nous utilisons Redis - nous devons donc vraiment trouver un moyen de gérer l'expiration des noms de file d'attente sur Redis

Ouais, nous avons un problème similaire avec BullMQ avec Redis. Mon idée est d'écrire CronJob pour Kubernetes qui effacerait les files d'attente à chaque fois.

Cette page vous a été utile?
0 / 5 - 0 notes