优化 — Python 文档
优化
简介
默认配置做了很多妥协。 它对于任何一种情况都不是最佳的,但在大多数情况下都足够好。
可以根据特定用例应用优化。
优化可以应用于运行环境的不同属性,无论是执行任务所需的时间、使用的内存量还是高负载时的响应能力。
确保运营
在 Programming Pearls 一书中,Jon Bentley 通过提出问题提出了粗略计算的概念;
❝ 一天从密西西比河流出多少水? ❞
本练习 * 的目的是表明系统可以及时处理的数据量是有限的。 信封计算可以用作提前计划的一种手段。
在芹菜中; 如果一个任务需要 10 分钟才能完成,并且每分钟有 10 个新任务进入,则队列永远不会为空。 这就是为什么监控队列长度非常重要的原因!
一种方法是通过 使用 Munin。 您应该设置警报,一旦任何队列达到不可接受的大小,它就会通知您。 通过这种方式,您可以采取适当的操作,例如添加新的工作节点或撤销不必要的任务。
一般设置
使用瞬态队列
Celery 创建的队列默认是持久的。 这意味着代理会将消息写入磁盘以确保即使代理重新启动也能执行任务。
但在某些情况下,消息丢失也没关系,因此并非所有任务都需要持久性。 您可以为这些任务创建一个 transient 队列以提高性能:
from kombu import Exchange, Queue
task_queues = (
Queue('celery', routing_key='celery'),
Queue('transient', Exchange('transient', delivery_mode=1),
routing_key='transient', durable=False),
)
task_routes = {
'proj.tasks.add': {'queue': 'celery', 'delivery_mode': 'transient'}
}
delivery_mode
改变了发送到这个队列的消息的方式。 值为 1 表示不会将消息写入磁盘,值为 2(默认值)表示可以将消息写入磁盘。
要将任务定向到新的瞬态队列,您可以指定 queue 参数(或使用 :setting:`task_routes` 设置):
task.apply_async(args, queue='transient')
有关详细信息,请参阅 路由指南 。
工人设置
预取限制
Prefetch 是一个继承自 AMQP 的术语,经常被用户误解。
预取限制是一个 limit,用于工作人员可以为自己保留的任务(消息)数量。 如果它为零,工作人员将继续消费消息,而不考虑可能有其他可用的工作节点可以更快地处理它们†,或者消息甚至可能无法放入内存。
工作线程的默认预取计数是 :setting:`worker_prefetch_multiplier` 设置乘以并发槽数 ‡(进程/线程/绿色线程)。
如果您有许多持续时间较长的任务,您希望乘数值为 one:这意味着它一次只会为每个工作进程保留一项任务。
但是,如果您有许多短期运行的任务,并且吞吐量/往返延迟对您很重要,那么这个数字应该很大。 如果消息已经被预取并且在内存中可用,则工作者能够每秒处理更多任务。 您可能需要进行试验才能找到最适合您的值。 在这些情况下,像 50 或 150 这样的值可能有意义。 说 64 或 128。
如果您有长时间和短期运行任务的组合,最好的选择是使用两个单独配置的工作节点,并根据运行时间路由任务(参见 路由任务 )。
一次预约一项任务
任务消息只有在任务被确认后才从队列中删除,所以如果worker在确认任务之前崩溃,它可以重新传递给另一个worker(或恢复后相同)。
当使用默认的提前确认时,预取乘数设置为 one,意味着 worker 最多会为每个 worker 进程保留一个额外任务:或者换句话说,如果 worker 以 -c 10
,worker 最多可以保留 20 个任务(10 个已确认的任务正在执行,10 个未确认的保留任务)。
用户经常会问是否可以禁用“预取任务”,但他们真正的意思是让一个工作进程只保留与工作进程一样多的任务(-c 10
的 10 个未确认任务)
这是可能的,但也必须启用 延迟确认 。 在默认行为上使用这个选项意味着一个已经开始执行的任务将在电源故障或工作实例突然被杀死的情况下重试,所以这也意味着任务必须是 幂等
您可以使用以下配置选项启用此行为:
task_acks_late = True
worker_prefetch_multiplier = 1
脚注
- *
- 该章节可在此处免费阅读:信封背面。 这本书是经典的文本。 强烈推荐。
- †
- RabbitMQ 和其他代理以循环方式传递消息,因此这不适用于活动系统。 如果没有预取限制并且您重新启动集群,则节点启动之间会有时间延迟。 如果有 3 个离线节点和 1 个活动节点,则所有消息都将传递到活动节点。
- ‡
- 这是并发设置; :setting:`worker_concurrency` 或
celery worker -c
选项。