Python分布式任务队列Celery中如何配置每个worker执行任务的数量限制?
我这边本机起了两个 worker ,然后设置了 CELERYD_PREFETCH_MULTIPLIER 为 1 。
但是跑起来以后,发现 STARTED 和 RECEVED 都有一大把,结果把我机器给跑崩了。
本来觉得是在 celery 起的 task 函数,里面的线程可能没优化好,导致这种情况,但后来觉得应该不会一次性 start 这么多的 task 啊。
个人觉得应该是一个 worker 同时只会解决一个 task 才对,或者这个解决的量是可以配置的,我这里没找到配置选项。。。
大家有没有什么好的办法,跪求解决方案!
Python分布式任务队列Celery中如何配置每个worker执行任务的数量限制?
新版本的 settings 名子改了, worker_prefetch_multiplier = 1 试试
在Celery中限制每个worker执行任务的数量,可以通过--max-tasks-per-child参数或worker_max_tasks_per_child配置项来实现。
1. 命令行启动时直接指定:
celery -A proj worker --max-tasks-per-child=100
这样每个worker子进程在执行100个任务后会被重启。
2. 在Celery配置文件中设置:
# celeryconfig.py
worker_max_tasks_per_child = 100
3. 在应用配置中设置:
app.conf.worker_max_tasks_per_child = 100
这个限制主要是为了防止内存泄漏,worker在执行指定数量的任务后会自动重启。如果需要限制并发任务数(同时执行的任务数量),应该使用--concurrency参数。
总结:用worker_max_tasks_per_child控制单个worker进程的最大任务数。
你设置的这是 fetch 的数量啊,不是 execute 的数量
先谢谢这位兄弟,不过我设置了 worker_prefetch_multiplier = 1 并没有起作用。
另外,我看到网上有解释,“ celery 中的一个 worker 其实是代表一个进程池,一个进程池是由一个父进程和多个子进程组成, 貌似父进程不干事,只用于分配 task ,子进程数默认是 CPU 核数”
故而我也试着配置了 CELERYD_MAX_TASKS_PER_CHILD = 2 ,但是貌似没起作用。
还是每个 worker 分配 start 了好几个 task , RECEVED 也一大把。
另外,我想问问大家怎么一次性,把那么多起来的 task 全部结束掉,每次 terminate 好多次。
兄弟求配置参数。。我没找到。。
非常感谢兄弟,确实有效,要是能直接写到配置里就更好了, hhhh
另外兄弟知道把那么 start 和 receive 后 task 全部结束掉么?
我每次都是直接 ctrl+C 把 worker 结束掉,因为用的 redis 作中间件,最后还会手动清理 redis 的缓存内容,不然它还会一直运行下去。
不过这样好像不太正规,也有点 bug 。
犯不着写配置文件里啊,反正你也得从 celery worker 命令行启动,多个-c 参数的小事而已
听不懂“把那么 start 和 receive 后 task 全部结束掉”
我的意思是:前台已经发了任务,存在了中间件( redis ),然后后台取了任务,有的已经 start ,有的还在 receive 状态,如何把这些废弃的任务全部结束掉。
我直接把那些 worker ctrl+c 掉的话,重新启动 worker 时,那些被废弃的任务还会继续跑。
这细节动作我就没注意观察过了
诶按说 redis 作为队列的话,取出来是不会放回去的啊?
并没有用 multi 喔,至于您说的 queuename 是 task 名么?类似于“ e1e10f99-fb7b-42a4-b627-7ea0e74daf90 ”?我那边用 flower 控制的,但也没有看见批量清除的法子,有点头疼。。
没,我猜是放到了 redis 里面的,清除 redis 后过会儿会结束。
但清除 redis 后再启动时, celery 还会调度一会儿 task ,这部分不知道是存在哪儿的,我一直很奇怪。
看配置项result_backend, task 信息存在 result_backend 配置对应位置,还有result_expires配置项,所有 task 默认存 1 天
不过 celelry 命令行有参数能干掉所有任务
谢谢兄弟,刚找了下干掉所有任务的参数,不过没找到。。有点伤
celery -h 其他配置项就不说了
看一下命令行说明<br>celery purge<br><br>返回<br>WARNING: This will remove all tasks from queue: celery.<br> There is no undo for this operation!<br><br>(to skip this prompt use the -f option)<br><br>Are you sure you want to delete all tasks (yes/NO)? <br>
这是我本机的提示
不知他能否干掉已经被 fetch 的命令,需要你排查
3ks ,我明天看看~~
http://docs.celeryproject.org/en/latest/userguide/configuration.html
参数配置都在这里,新旧配置的 key 对照表也有。
CELERYD_PREFETCH_MULTIPLIER = n
worker_prefetch_multiplier = n
这个是任务预取功能,就是每个工作的进程/线程/绿程在获取任务的时候,会尽量多拿 n 个,以保证获取的通讯成本可以压缩,在每个任务很短(明显小于 1 秒)情况下,是值得调大的,而且推荐是 2 的幂。0 表示尽可能多拿。如果 1 个都不想多拿,那么除了设置 1 外,还需要 设置 task_acks_late 为 true,如果你的任务不是幂等(可以重复调用)的话,可能会有问题。详细解释参考: http://docs.celeryproject.org/en/latest/userguide/optimizing.html
task_acks_late = True
worker_prefetch_multiplier = 1
CELERYD_MAX_TASKS_PER_CHILD = n
worker_max_tasks_per_child = n
这个表示每个工作的进程/线程/绿程 在执行 n 次任务后,主动销毁,之后会起一个新的。主要解决一些资源释放的问题。
CELERY_TASK_RESULT_EXPIRES = s
result_expires = s
这个表示保存任务结果的时长,这个时间会被设置到 redis 里面(假设 backend 是 redis ),如果抓取数据量大的话,是可以缩短保存的时间,节省 backend 的资源( redis 主要是内存)消耗,默认是 24 小时( 86400 ),单位是秒。
===分割线===
已经 fetch 的任务,要么等执行完毕,要么等 kill 掉。要注意 soft kill 和 hard kill 的区别,没记错的话是 TERMINAL 和 kill -9 的区别。soft kill 会执行完当前的 task,但是,prefetch 的会丢失。在 pycharm 里,我第一次 ctrl+c 是软 kill,可能会等上一会儿,第二次 ctrl+c 是硬 kill,直接停掉进程。
没有 fetch 的任务可以 purge 清理调队列中的。
根据选择的 pool 类型不同,可以有 solo (单进程) prefork (进程池) threading (线程池) gevent (协程池)和 eventlet (协程池)。4.x 好像废弃了线程池,主要的原因我猜可能和 GIL 有关。进程池比较耗内存,好处是所有工作线程资源都是隔离的,如果配置动态数量的挺好用。协程池 则对于 IO 密集型工作比较有优势。所有的并发数量默认是 cpu core 的数量,4 核就是 4,可以根据实际情况调大。
非常感谢您,很详细,这帖子我差点都忘了。。另外,我想请教下您,如果想批量 kill 一批机器的 task,应该咋弄,我通常是直接 grep celery 的所有进程,然后 kill -9。
但是这样就有个毛病,我批量 kill 集群中的 task 时会出现问题,只有一台一台机器去手动操作。
另外,您说如果 celery 卡住的时候,重启所有 pool 有用么?话说我以前配置了 pool 的安全选项,还是不能在 flower 直接重启。
这是 17 年的帖子了…不过还是谢谢兄 dei~
兄弟,你的 task_acks_late 这个参数对我帮助太大了,这个问题我找了两个礼拜。
因为我的一个 task 可能要执行 10s~600s 不等,我的 worker 同时只能执行一个 task。所以我不希望任何一个 worker 在执行一个任务的时候,再接收其他任务(除非所有 worker 都在执行任务。)


