Python 异步任务队列选型:从 Celery 迁到 Arq 的一次实践

举报
yd_274534175 发表于 2026/10/29 08:31:51 2026/10/29
【摘要】 把日均 3 万任务的 Celery 队列迁到 Arq 的完整过程:worker 内存 200MB 降到 45MB,冷启动 1.5s 降到 0.2s,附代码对比与迁移步骤。

Python 异步任务队列选型:从 Celery 迁到 Arq 的一次实践

背景

项目早期用 Celery + Redis 跑异步任务,功能没问题,但运维成本一直在涨:worker 内存常驻 200MB 起、beat 调度的时区坑、还有任务超时后不重试导致消息丢失。业务量不大(日均 3 万任务),属于典型的"用重锤敲钉子"。后来换成 Arq,代码量砍了一半。

Celery 的三个痛点

**1. 启动开销大**:单个 worker 冷启动要 1.5 秒,容器水平扩容时抖动明显。

**2. 配置分散**:broker、result backend、队列路由、序列化、时区,散落在五六个地方,新人基本看不懂。

**3. 超时语义模糊**:`task_time_limit` 触发后任务直接被杀,队列里的消息状态不一致,需要额外写补偿逻辑。

Arq 的写法

Arq 是基于 asyncio 的轻量队列,一个 worker 就是一个事件循环:

import asyncio
from arq import create_pool
from arq.connections import RedisSettings

async def send_mail(ctx, addr, subject):
    await asyncio.sleep(0.1)
    return f"sent to {addr}"

class WorkerSettings:
    functions = [send_mail]
    redis_settings = RedisSettings(host="127.0.0.1", port=6379)
    max_jobs = 20
    job_timeout = 60

投递任务:

redis = await create_pool(RedisSettings())
await redis.enqueue_job("send_mail", "a@b.com", "hello")

就这么多。没有额外的配置文件,没有 beat 进程(定时用 cron 表达式挂在 WorkerSettings 里)。

迁移过程

• 第一步:把 Celery task 改成 `async def` + 第一个参数 `ctx`,逻辑几乎不用动

• 第二步:`delay()` 换成 `enqueue_job()`,注意参数要可序列化

• 第三步:重试逻辑用 `max_tries` 参数,Arq 自动按指数退避重排

• 第四步:原来的 beat 定时任务迁到 `cron_jobs`,时区显式写 UTC

结果

• worker 内存 200MB → 45MB

• 冷启动 1.5s → 0.2s

• 代码行数 800 → 380

• 任务积压监控沿用 Redis 队列长度,不用改

什么时候不该换

如果任务有复杂的依赖链(chain、chord、group),或者需要跨语言 worker,Celery 生态还是更成熟。Arq 适合"就是想把函数丢到后台跑"的场景,别硬套。

小结

选型的第一原则是匹配规模。日任务不到十万级的时候,队列本身的复杂度往往比业务还高,轻一点反而更稳。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。