Celery适合用于多个小型分布式系统吗?

6 投票
2 回答
2381 浏览
提问于 2025-04-16 04:54

我正在写一些软件,目的是管理几百个在“现场”的小系统,这些系统通过间歇性的3G(或者类似的)连接进行通信。

总部需要向现场的系统发送任务(比如,“报告你的状态”,“更新你的软件”等),而现场的系统也需要向服务器发送任务(比如,“检测到故障”,“这里有一些数据”等)。

我花了一些时间研究Celery,它看起来非常合适:在总部运行的celeryd可以收集现场系统的任务,而在现场系统上运行的celeryd可以收集发回服务器的任务,这些任务可以在客户端可用时进行交换。

那么,Celery适合解决这个问题吗?具体来说:

  • 大部分任务会指向某个特定的工作者(比如,“把‘get_status’任务发送给‘system51’”)——这会有问题吗?
  • 它能否优雅地处理不好的网络状况(比如,连接断掉)?
  • 如果使用RabbitMQ作为后端,有哪些功能是只有在那种情况下才能使用的?(我不想在现场系统上运行RabbitMQ)
  • 如果我按照我描述的方式使用Celery,还有其他原因会让我的生活变得困难吗?

谢谢!

(有人可能会说Celery有些过于复杂,但还有其他原因让我觉得它会让我的生活更简单,所以我想考虑一下)

2 个回答

1

我可能会搭建一个(django)网络服务来接收请求。这个网络服务可以负责检查请求的有效性,并且拒绝那些不好的请求。然后,celery 就可以专心去处理工作了。

不过,这样的话,远程设备就需要定期去查询这个网络服务,看看它们的任务是否完成。这种做法是否合适,得看你具体在做什么。

12

大部分任务会指派给某个特定的工作者(比如,“把‘获取状态’的任务发给‘system51’”)——这样会有问题吗?

一点问题都没有。只需要为每个工作者创建一个队列,比如说每个节点都监听一个叫做 default 的轮询队列,而每个节点都有一个以其节点名称命名的队列:

(a)$ celeryd -n a.example.com -Q default,a.example.com
(b)$ celeryd -n b.example.com -Q default,b.example.com
(c)$ celeryd -n c.example.com -Q default,c.example.com

直接把任务发给某个节点很简单:

$ get_status.apply_async(args, kwargs, queue="a.example.com")

或者通过配置使用一个 Router 来实现:

# Always route "app.get_status" to "a.example.com"
CELERY_ROUTES = {"app.get_status": {"queue": "a.example.com"}}

它能优雅地处理不好的网络情况吗(比如,连接中断)?

工作者能优雅地从与代理的连接失败中恢复过来。(至少对于RabbitMQ是这样,我不确定其他后端是否也能这样,但这很容易测试和修复(你只需要把相关的异常添加到一个列表中)

对于客户端,如果连接断了,你总是可以重试发送任务,或者你可以设置RabbitMQ的高可用性:http://www.rabbitmq.com/pacemaker.html

如果不使用RabbitMQ作为后端,有什么功能是无法使用的?(我不想在现场系统上运行RabbitMQ)

远程控制命令,以及仅支持“直接”交换(不支持“主题”或“广播”)。不过在Kombu (http://github.com/ask/kombu)中会支持这些功能。

我真的建议你重新考虑使用RabbitMQ。你觉得它不合适的原因是什么?在我看来,我不会去找其他类似的系统,(也许如果系统是临时的且不需要消息持久化,可以考虑ZeroMQ)。

如果我像我描述的那样使用Celery,还有其他原因会让我的生活变得困难吗?

从你上面的描述来看,我想不出有什么问题。由于并发模型是多进程的,它确实需要一些内存(我正在努力添加对线程池和事件池的支持,这在某些情况下可能会有所帮助)。

可以说Celery有点过于复杂,但也有其他原因让它能让我生活更轻松,所以我想考虑一下。

在这种情况下,我觉得你说“过于复杂”有点轻率。这真的取决于你需要写多少代码和测试。如果没有它,我觉得改进一个已经存在的通用解决方案更好,从理论上讲,它应该能很好地适应你的应用。

撰写回答