Celery: [K8S] LivenessProbe und ReadinessProbe für Sellerie-Beat und Arbeiter

Erstellt am 8. Juni 2017  ·  31Kommentare  ·  Quelle: celery/celery

Hallo,

Ich verwende Kubernetes, um meine Python-Anwendung bereitzustellen. Kubernetes bieten eine LivenessProbe und ReadinessProbe, siehe hier .

Wie kann ich überprüfen, ob mein Sellerie-Beat oder Sellerie-Arbeiter lebt und sich in einem korrekten Zustand befindet?
Die PID ist keine Lösung, da sie beispielsweise nicht zum Abfangen eines Deadlocks verwendet werden kann.

Vielen Dank im Voraus für Ihre Hilfe,

Freundliche Grüße,

Deployment Question Needs Verification ✘

Hilfreichster Kommentar

celery inspect ping funktioniert, aber Sie benötigen bash , um die Umgebungsvariable wie folgt zu ersetzen:

        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

Alle 31 Kommentare

Sellerie verfügt über eine Überwachungs-API, die Sie verwenden können.
Ein Pod sollte als live betrachtet werden, wenn der Sellerie-Arbeiter einen Herzschlag sendet.
Ein Pod sollte als bereit betrachtet werden, wenn der Mitarbeiter das Worker-Online- Ereignis gesendet hat.

Wenn Sie spezielle Probleme oder Funktionsanforderungen haben, öffnen Sie bitte ein separates Problem.

Würde das funktionieren?

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

@ 7wonders Sie müssten zuerst den Namen des Sellerieknotens extrahieren. Diese ReadinessProbe schlägt fehl, wenn eine Sellerie-Instanz ausfällt, was nicht das ist, was Sie wollen.

@thedrow Hmm , ich denke, es ist tatsächlich so, dass es auch dann erfolgreich sein wird, wenn der eigentliche Knoten ausgefallen ist, aber ein anderer ist in Ordnung, was ebenfalls kein großartiges Ergebnis ist.

Sieht aus wie

/bin/sh -c 'exec celery -A path.to.app inspect ping -d celery@$HOSTNAME' ist gut genug für die Bereitschaftsprüfung und überprüft nur einen Knoten.

Beachten Sie, dass das Ausführen dieses Befehls in einigen Apps einige Sekunden dauern kann, wenn die volle CPU UND die Kubernet-Standardeinstellungen alle 10 Sekunden verwendet werden.

Es ist daher viel sicherer, einen hohen Zeitraum von Sekunden zu haben (unser Wert ist auf 300 eingestellt).

@redbaron hat dieser Befehl für Sie funktioniert? Wenn es funktioniert, wie lauten dann die Einstellungen für Lebendigkeit und Bereitschaft?

Aus irgendeinem Grund ist diese Bereitschaftssonde für uns bei weitem nicht zufriedenstellend. Die Inspektion reagiert nicht deterministisch ohne Belastung unseres Clusters. Wir führen das Format folgendermaßen aus:

Sellerie inspizieren Ping -b " Redis: // Archii-Redis-Master : 6379" -d Sellerie @ Archii-Task-Crawl-Integration-7d96d86b9d-Jwtq7

Und mit normalen Ping-Zeiten (10 Sekunden) wird unser Cluster vollständig durch den CPU-Sellerie getötet, der benötigt wird.

~ Ich benutze dies für die Lebendigkeit mit einem Intervall von 30 Sekunden: sh -c celery -A path.to.app status | grep "${HOSTNAME}:.*OK" ~
Ich benutze dies für die Lebendigkeit mit einem 30s Intervall: sh -c celery -A path.to.app inspect ping --destination celery@${HOSTNAME}
Scheint keine zusätzliche Last zu verursachen, ich leite eine Flotte von weit über 100 Arbeitern.

Bereitschaftsprüfungen sind nicht erforderlich, Sellerie wird niemals in einem Dienst verwendet. Ich habe gerade minReadySeconds: 10 was gut genug ist, um den Start des Workers in fortlaufenden Bereitstellungen zu verzögern, aber es hängt natürlich von der Startzeit von Sellerie für Ihr Projekt ab. Untersuchen Sie daher die Protokolle und legen Sie sie entsprechend fest.

Bereitschaftssonden sind auch dann noch nützlich, wenn sie nicht in einem Dienst verwendet werden. Insbesondere wenn Sie eine Bereitstellung von Mitarbeitern durchführen und sicherstellen möchten, dass Ihre Bereitstellung erfolgreich war, verwenden Sie normalerweise kubectl rollout status deployment . Ohne Readiness-Tests haben wir schlechten Code bereitgestellt, der Sellerie nicht gestartet hat und es nicht wusste.

Meine Lösung war:

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

Andere scheinen nicht zu funktionieren 🤷‍♂️

Danke @yardensachs!
Verbringen Sie viel Zeit mit dem Debuggen, was mit anderen Lösungen nicht stimmt, aber auf keinen Fall
Scheint, als würde der Befehl celery inspect ping nicht exit (0) oder etwas auf diese Weise zurückgeben

celery inspect ping funktioniert, aber Sie benötigen bash , um die Umgebungsvariable wie folgt zu ersetzen:

        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

gut zu wissen

Am Ende haben wir Sellerie-Inspektions-Ping aus unseren Lebendigkeitssonden herausgerissen, weil wir festgestellt haben, dass der Ping unter schwererer Last nur minutenlang hängen blieb, obwohl die Jobs einwandfrei verarbeitet wurden und es keinen Rückstand gab. Ich habe das Gefühl, dass es etwas mit der Verwendung von Eventlet zu tun hat, aber wir untersuchen es weiterhin.

@WillPlatnick Das wird mit 5.0 nicht passieren, da Sellerie asynchron ist und daher Kapazität für Kontroll-Coroutinen reserviert ist.

Ich habe Probleme mit inspect ping / Zombie-Prozesse erzeugen:

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>
...

Jemand anderes, der darauf stößt? Es gibt kein --pool Argument, um eine einzelne Prozessausführung zu erzwingen.

Kann ich fragen, was Sie anstelle von celery inspect ping @WillPlatnick verwenden? Wir haben ein ähnliches Problem festgestellt, bei dem die Sonde unter starker Last ausfällt.

@mcyprian Wir haben die Lebendigkeitssonde losgeworden. Mein Bauch sagt mir, dass es etwas mit Eventlet zu tun hat, aber wir haben es nicht zur Priorität gemacht, es herauszufinden.

Wir haben das gleiche CPU-Problem mit Redis Broker

Hat jemand eine Lösung gefunden?
Wir haben auch mit der Planung von "debug_task" in der Warteschlange experimentiert, deren Name auf dem Containernamen basiert. Das Problem ist, dass wir jetzt Tonnen von alten Warteschlangen in RabbitMQ haben

Bitte beachten Sie, dass mit

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

Wie unter https://github.com/celery/celery/issues/4079#issuecomment -437415370 vorgeschlagen, führt dies zu massiven Fehlerberichten auf rabbitmq, siehe https://github.com/celery/celery/issues/4355#issuecomment - 578786369

Ich denke, ich habe einen Weg gefunden, um die CPU-Auslastung von Inspect Ping zu reduzieren.

Sellerie -b amqp: // Benutzer: pass @ rabbitmq : 5672 / vhost inspizieren Ping

Das Nicht-Laden der Sellerie-Konfigurationen mit -A path.to.celery half sicherlich bei der CPU-Nutzung.
könnte jemand überprüfen.

Ich denke, ich habe einen Weg gefunden, um die CPU-Auslastung von Inspect Ping zu reduzieren.

Sellerie -b amqp: // Benutzer: pass @ rabbitmq : 5672 / vhost inspizieren Ping

Das Nicht-Laden der Sellerie-Konfigurationen mit -A path.to.celery half sicherlich bei der CPU-Nutzung.
könnte jemand überprüfen.

Nett! Es ist viel besser als mit der geladenen App.
Aber wir haben immer noch den enormen Aufwand für einen Python-Prozess, der + Sellerieimport startet. Ich würde immer noch eine hohe Periode empfehlen.

Hallo,
Sellerie inspizieren Ping-A app.tasks -d Sellerie @ $ HOSTNAME gibt mir "Fehler: Broadcast wird nicht von Transport 'sqs' unterstützt".
Ich verwende SQS als Broker. Dies bedeutet also, dass der Befehl 'inspect' / 'status' mit SQS nicht funktioniert.

Wir haben festgestellt, dass alle Funktionen der Fernbedienung im Maßstab dazu führen, dass die Redis-Instanz aufgrund von Setzbefehlen für die Taste kombu.pidbox in der CPU ansteigt. Daher können wir Ping, Status oder Inspektion nicht so verwenden, wie sie sind Alle verwenden die Fernbedienung und versuchen, die Fernbedienung für den Anwendungsfall in der Produktion zu deaktivieren.

Mir scheint, eine dedizierte Warteschlange für Gesundheitschecks ist der richtige Weg, aber ich bin mir überhaupt nicht sicher

Hat jemand eine andere Richtung, die keine Fernbedienung zum Testen von Gesundheitsprüfungen beinhaltet?

Wir verwenden seit einiger Zeit dedizierte Warteschlangen für Integritätsprüfungen mit RabbitMQ-Räumungsrichtlinien (Warteschlangen werden automatisch gelöscht) erfolgreich und sind mit der Lösung zufrieden. Meistens, weil bei dieser Überprüfung tatsächlich überprüft wird, ob der Mitarbeiter die Aufgabe verarbeitet und beendet. Seit wir es eingeführt haben, hatten wir keine Probleme mehr mit festgefahrenen Arbeitern.

@bartoszhernas etwas dagegen, Code dafür zu teilen? Stellt ihr diese per Beat in die Warteschlange und dann holen die Arbeiter sie ab?

Ich würde gerne den Code + den Abschnitt über die Lebendigkeitssonde sehen

Hallo, der Code ist wirklich einfach:

In Kubernetes gebe ich den Warteschlangennamen basierend auf POD_NAME an und übergebe ihn an das Livecheck-Skript:

        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)

(Sie müssen bash -c verwenden, da Kubernetes ENVs nicht erweitert, wenn Sie versuchen, es direkt als Befehl zu übergeben.)

Dann richtet die Datei celery_liveness_probe.py nur Django ein, um Sellerie verwenden zu können, und plant die Aufgabe in der POD-Warteschlange

# 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)

Die Health Check-Funktion sendet die Aufgabe und wartet auf die Ergebnisse

    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

Also im Grunde: Senden Sie eine Aufgabe, und wenn sie Ergebnisse zurückgibt, ist der Arbeiter gesund. Wenn der Arbeiter stecken geblieben ist (was oft passiert ist), werden die Aufgaben nie beendet, der Pod wird neu gestartet und alles wird wieder normal.

Die einzige Einschränkung ist, dass Sie mit alten Warteschlangen umgehen müssen. Mit RabbitMQ ist es einfach. Wir haben nur eine Ablaufrichtlinie für die Warteschlange eingerichtet
https://www.rabbitmq.com/ttl.html#queue -ttl

@bartoszhernas danke für das Teilen des Codes!

Wie Sie bereits sagten, sind meine Warteschlangen dynamisch und wir verwenden Redis. Daher müssen wir wirklich einen Weg finden, um mit dem Ablauf der Warteschlangennamen in Redis umzugehen

Ja, wir haben ein ähnliches Problem mit BullMQ mit Redis. Meine Idee ist es, CronJob für Kubernetes zu schreiben, das die Warteschlangen jedes Mal löscht.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen