简体   繁体   English

使用 redis 在 celery 中的任务优先级

[英]Task priority in celery with redis

I would like to implement a distributed job execution system with celery.我想用芹菜实现分布式作业执行系统。 Given that rabbitMQ doesn't support priorities and I'm painfully needing this feature, I turned to celery+redis.鉴于rabbitMQ 不支持优先级并且我非常需要这个功能,我转向了celery+redis。

In my situation, the tasks are closely related to hardware, for example, task A could only run on Worker 1 since only the PC of Worker 1 has got the necessary hardware.在我的情况下,任务与硬件密切相关,例如任务 A 只能在 Worker 1 上运行,因为只有 Worker 1 的 PC 有必要的硬件。 I set the CONCURRENCY of each worker to 1 so that a worker will only run one task each time.我将每个工作人员的 CONCURRENCY 设置为 1,以便工作人员每次只运行一项任务。 Each task takes about 2 minites.每个任务大约需要 2 分钟。

To implement the priority feature, first of all I tried adding priority argument when calling apply_async() , for example apply_async(priority=0) and apply_async(priority=9) .为了实现优先级功能,首先我尝试在调用apply_async()时添加priority参数,例如apply_async(priority=0)apply_async(priority=9) In this test I launched only one Worker with COCURRENCY=1, and kicked off 10 tasks one by one with different priorities.在本次测试中,我只启动了一个 COCURRENCY=1 的 Worker,并按照不同的优先级依次启动了 10 个任务。 I expected to see the tasks kicked off by apply_async(priority=0) will run in priority, but unfortunately they're just started as the kicking-off order.我希望看到由apply_async(priority=0)启动的任务将优先运行,但不幸的是,它们只是作为启动顺序启动。

Then I try to do some work around.然后我尝试做一些工作。 I cloned each task, so for each one I have task_high and task_low, decorated by @celery.task(priority=0) and @celery.task(priority=1) .我克隆了每个任务,因此对于每个任务,我都有 task_high 和 task_low,由@celery.task(priority=0)@celery.task(priority=1) Then I did the same test as above, this time it was better, when the kicking-off order is "HH-LLLL-HHHH", the real order comes out to be "HH-LHHLHLLH".然后我做了和上面一样的测试,这次更好,当开球顺序是“HH-LLLL-HHHH”时,真正的顺序是“HH-LHHLHLLH”。 I suppose redis did some scheduling and balancing work here.我想 redis 在这里做了一些调度和平衡工作。

But this still can't meet my expectation.但这仍然达不到我的期望。 I hope to get an order like "HHHHHH-LLLL", because for some tasks I have only one proper machine with the necessary hardware and hope the high-priority task to run as soon as possible.我希望得到像“HHHHHH-LLLL”这样的命令,因为对于某些任务,我只有一台具有必要硬件的合适机器,并希望高优先级任务尽快运行。

I've searched for other work around on the Internet, for example using two queues, one for high-priority tasks and the other for low-priority, and using 2 machines for the former and 1 machine for the latter.我在 Internet 上搜索了其他工作,例如使用两个队列,一个用于高优先级任务,另一个用于低优先级任务,前者使用 2 台机器,后者使用 1 台机器。 But since my hardware is quite limited, this doesn't work for me.但是由于我的硬件非常有限,这对我不起作用。

Could you please give some suggestions?你能给一些建议吗?

The Celery Redis transport does honor the priority field, but Redis itself has no notion of priorities. Celery Redis 传输确实遵循优先级字段,但 Redis 本身没有优先级的概念。

The priority support is implemented by creating n lists for each queue and using that order in the BRPOP command.通过为每个队列创建 n 个列表并在 BRPOP 命令中使用该顺序来实现优先级支持。 I say n here because even though there are 10 (0-9) priority levels, these are consolidated into 4 levels by default to save resources.我在这里说n是因为即使有 10 (0-9) 个优先级,默认情况下它们也被合并为 4 个级别以节省资源。 This means that a queue named celery will really be split into 4 queues:这意味着一个名为celery的队列将真正分为 4 个队列:

['celery0', 'celery3`, `celery6`, `celery9`]

If you want more priority levels you can set the priority_steps transport option:如果你想要更多的优先级,你可以设置priority_steps传输选项:

BROKER_TRANSPORT_OPTIONS = {
    'priority_steps': list(range(10)),
}

That said, note that this will never be as good as priorities implemented at the server level, and may be approximate at best.也就是说,请注意,这永远不会像在服务器级别实施的优先级那样好,最多可能是近似的。 But it may still be good enough for your application.但它对于您的应用程序来说可能仍然足够好。

Celery docs about redis message priorities is here redis-message-priorities ,you can customize priority levels.Take 10 for example:关于 redis 消息优先级的 Celery 文档在这里redis-message-priorities ,您可以自定义优先级。以 10 为例:

  1. set the priority_steps transport option设置 priority_steps 传输选项
app.conf.broker_transport_options = {
    'priority_steps': list(range(10)),
    'queue_order_strategy': 'priority',
}
  1. start celery worker in normal way以正常方式启动芹菜工人
celery -A tasks worker --loglevel=info
  1. calling tasks, 0 being highest priority and 9 being lowest priority调用任务,0 为最高优先级,9 为最低优先级
custom_priority=5 
task.apply_async(args=[arg1, arg2], kwargs={'kwarg1': 'x', 'kwarg2': 'y'},priority=custom_priority)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM