Celery: [K8S]芹菜拍子和工人的活力探针和就绪探针

创建于 2017-06-08  ·  31评论  ·  资料来源: celery/celery

你好,

我正在使用Kubernetes部署我的python应用程序,Kubernetes提供了一个livenessProbe和readinessProbe参见此处

我该如何检查我的芹菜节拍或芹菜工人是否还活着并且处于正确状态?
PID不是解决方案,因为它不能用于捕获死锁。

在此先感谢您的帮助,

此致,

Deployment Question Needs Verification ✘

最有用的评论

celery inspect ping确实可以工作,但是您需要bash来替换环境变量,如下所示:

        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

所有31条评论

Celery具有可以使用的监视API
如果芹菜工人发出心跳信号,则应将豆荚视为带电的。
如果工作人员发送了工作程序联机事件,则应将其视为准备就绪。

如果您有特定问题或功能要求,请另开一本。

这行得通吗?

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

@ 7wonders您需要首先提取celery节点名称。 如果任何芹菜实例发生故障(这不是您想要的),则此readinessProbe将会失败。

@thedrow嗯,我认为即使实际节点发生故障,它实际上也会成功,但是另一个节点还可以,这也不是一个好结果。

好像

/bin/sh -c 'exec celery -A path.to.app inspect ping -d celery@$HOSTNAME'足以用于准备情况检查并仅验证一个节点。

请注意,在某些应用中,使用完整的CPU运行此命令可能需要花费几秒钟,而kubernetes的默认设置是每10秒运行一次。

因此,使用高周期秒数(我们将其设置为300)要安全得多。

@redbaron该命令对您

由于某种原因,这种准备情况调查对我们而言还远远不能令人满意。 检查结果不确定,在群集上没有负载。 我们运行这样的格式:

celery检查ping -b“ redis:// archii-redis-master :6379” -d celery @ archii-task-crawl-integration-7d96d86b9d-jwtq7

在正常的ping时间(10秒)下,我们的集群完全被CPU celery要求杀死了。

〜我以30秒的间隔将其用于活动: sh -c celery -A path.to.app status | grep "${HOSTNAME}:.*OK"
我以30秒的间隔使用此功能: sh -c celery -A path.to.app inspect ping --destination celery@${HOSTNAME}
似乎没有造成任何额外的负担,我经营着一支由100多名工人组成的车队。

无需准备就绪探针,Celery永远不会在服务中使用。 我只是设置了minReadySeconds: 10 ,它足以延迟滚动部署中的工作程序启动,但是显然它取决于您项目的Celery启动时间,因此请检查日志并进行相应设置。

即使未在服务中使用就绪探针,它们也仍然有用。 具体来说,当您部署worker并想确保部署成功时,通常使用kubectl rollout status deployment 。 没有准备就绪的探针,我们就部署了无法启动celery也不知道的错误代码。

我的解决方案是:

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

其他人似乎不起作用🤷‍♂️

谢谢@yardensachs!
花很多时间来调试其他解决方案的问题,但是没有办法
好像celery inspect ping命令不会返回exit(0)或类似的方式

celery inspect ping确实可以工作,但是您需要bash来替换环境变量,如下所示:

        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

很高兴知道

我们最终从芹菜探伤仪中剔除芹菜,因为我们发现在负载较重的情况下,即使作业进行得很好并且没有积压,ping每次只能挂几分钟。 我觉得它与使用eventlet有关,但是我们正在继续研究它。

@WillPlatnick 5.0不会发生这种情况,因为Celery将是异步的,因此将保留控制协程的容量。

我在使用inspect ping产生失效/僵尸进程时遇到麻烦:

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

还有其他人遇到吗? 没有用于强制单个进程执行的--pool参数。

我能问问您在用什么,而不是celery inspect ping @WillPlatnick吗? 我们也遇到过类似的问题,探针在重负载下会失败。

@mcyprian我们摆脱了

我们与Redis Broker遇到相同的CPU问题

有没有人找到解决方案?
我们还在尝试根据容器名称在队列上调度“ debug_task”。 问题在于,RabbitMQ现在有很多旧队列

请注意,使用

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

https://github.com/celery/celery/issues/4079#issuecomment -437415370上建议的那样,将导致关于Rabbitmq的大量错误报告,请参阅https://github.com/celery/celery/issues/4355#issuecomment- 578786369

我想我已经找到一种减少检查ping的CPU使用率的方法。

celery -b amqp:// user:pass @ rabbitmq :5672 / vhost检查ping

不使用-A path.to.celery加载celery配置肯定有助于使用cpu,
有人可以验证。

我想我已经找到一种减少检查ping的CPU使用率的方法。

celery -b amqp:// user:pass @ rabbitmq :5672 / vhost检查ping

不使用-A path.to.celery加载celery配置肯定有助于使用cpu,
有人可以验证。

好的! 这比加载应用程序要好得多。
但是,我们仍然需要从python进程开始+ celery import的庞大开销。 我仍然建议您选择高时期。

你好,
celery inspect ping -A app.tasks -d celery @ $ HOSTNAME给我“错误:传输'sqs'不支持广播”。
我使用SQS作为代理,所以这意味着'inspect'/'status'命令不能与SQS一起使用?

我们已经发现,由于在kombu.pidbox键上设置了命令,所有的远程控制功能都会导致Redis实例在CPU中尖峰运行,因此我们不能按原样使用ping或状态或检查全部使用远程控制,并尝试针对生产用例禁用远程控制。

在我看来,拥有专用的健康检查队列是正确的方法,但我不确定

有人有其他指示不涉及遥控器来测试健康检查吗?

我们将专用的运行状况检查队列与RabbitMQ逐出策略一起使用(队列会自动删除),目前已成功使用了一段时间,我们对该解决方案感到满意。 主要是因为此检查实际上是在检查工作者是否在处理任务并完成任务。 自从引入以来,我们不再遇到卡住工人的问题。

@bartoszhernas介意

希望看到代码+活动探针部分

嗨,代码真的很简单:

在Kubernetes中,我基于POD_NAME指定队列名称,并将其传递给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)

(您需要使用bash -c,因为在尝试直接将其作为命令传递时,Kubernetes不会扩展ENV)

然后celery_liveness_probe.py只是将Django设置为能够使用Celery并在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)

运行状况检查功能发送任务并等待结果

    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

基本上就是这样:发送任务,如果任务返回结果,那么工作人员就很健康。 如果工人卡住了(发生了很多次),那么任务将永远无法完成,Pod将重新启动,一切恢复正常。

唯一的警告是您需要处理旧队列,使用RabbitMQ很简单,我们只需在队列上设置到期策略
https://www.rabbitmq.com/ttl.html#queue -ttl

@bartoszhernas感谢您分享代码!

就像您说过的那样,我的队列是动态的,我们正在使用Redis-因此,我们确实需要找到一种方法来处理Redis上的队列名称过期

是的,我们在Redis的BullMQ中也遇到类似的问题。 我的想法是为Kubernetes编写CronJob,它将每隔一段时间清除队列。

此页面是否有帮助?
0 / 5 - 0 等级