为什么要使用celery

Celery是一个使用Python开发的分布式任务调度模块,因此对于大量使用Python构建的系统,可以说是无缝衔接,使用起来很方便。Celery专注于实时处理任务,同时也支持任务的定时调度。因此适合实时异步任务定时任务等调度场景。Celery需要依靠RabbitMQ等作为消息代理,同时也支持Redis甚至是Mysql,Mongo等,当然,官方默认推荐的是RabbitMQ。

broker的选择

虽然官方支持的broker有很多,包括RabbitMQ,Redis甚至是数据库,但是不推荐使用数据库,因为数据库需要不断访问磁盘,当你的任务量大了之后会造成很严重的性能问题,同时你的应用很可能也在使用同一个数据库,这样可能导致你的应用被拖垮。如果业务环境比较简单可以选择Redis,如果比较复杂选择RabbitMQ,因为RabbitMQ是官方推荐的,但是比Redis操作起来又相对复杂些。我的选择是broker用RabbitMQ,backend用Redis

celery不能用root用户启动问题 C_FORCE_ROOT environment

如果使用root用户启动celery会遇到下面的问题

Running a worker with superuser privileges when the
worker accepts messages serialized with pickle is a very bad idea!
If you really want to continue then you have to set the C_FORCE_ROOT
environment variable (but please think about this before you do).

解决办法:

from celery import Celery, platforms

platforms.C_FORCE_ROOT = True  #加上这一行

任务重复执行

celery执行定时任务的时候遇到了重复执行的问题,当时是用redis做broker和backend。
官方文档中有相关描述。

If a task is not acknowledged within the Visibility Timeout the task will
be redelivered to another worker and executed.

This causes problems with ETA/countdown/retry tasks where the time to execute exceeds the visibility timeout; in fact if that happens it will be executed again, and again in a loop.

So you have to increase the visibility timeout to match the time of the longest ETA you are planning to use.

Note that Celery will redeliver messages at worker shutdown, so having a long visibility timeout will only delay the redelivery of ‘lost’ tasks in the event of a power failure or forcefully terminated workers.

Periodic tasks will not be affected by the visibility timeout, as this is a concept separate from ETA/countdown.

You can increase this timeout by configuring a transport option with the same name:

BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 43200}

The value must be an int describing the number of seconds.

就是说当我们设置一个ETA时间比visibility_timeout长的任务时,每过一次 visibility_timeout 时间,celery就会认为这个任务没被worker执行成功,重新分配给其它worker再执行。
解决办法就是把 visibility_timeout参数调大,比我们ETA的时间差要大。celery本身的定位就主要是实时的异步队列,对于这种长时间定时执行,支持不太好。
但是第二天依然重复执行了。。。

最后我的解决方法是在每次定时任务执行完就在redis中写入一个唯一的key对应一个时间戳,当下次任务执行前去获取redis中的这个key对应的value值,和当前的时间做比较,当满足我们的定时频率要求时才执行,这样保证了同一个任务在规定的时间内只会执行一次。

使用不同的queue

当你有很多任务需要执行的时候,不要偷懒只使用默认的queue,这样会相互影响,并且拖慢任务执行的,导致重要的任务不能被快速的执行。鸡蛋不能放在同一个篮子里的道理大家都懂。
有一种简单的方式设置queue

Automatic routing

The simplest way to do routing is to use the CELERY_CREATE_MISSING_QUEUES setting (on by default).

With this setting on, a named queue that is not already defined in CELERY_QUEUES will be created automatically. This makes it easy to perform simple routing tasks.

Say you have two servers, x, and y that handles regular tasks, and one server z, that only handles feed related tasks. You can use this configuration:

CELERY_ROUTES = {'feed.tasks.import_feed': {'queue': 'feeds'}}

With this route enabled import feed tasks will be routed to the “feeds” queue, while all other tasks will be routed to the default queue (named “celery” for historical reasons).

Now you can start server z to only process the feeds queue like this:

user@z:/$ celery -A proj worker -Q feeds

You can specify as many queues as you want, so you can make this server process the default queue as well:

user@z:/$ celery -A proj worker -Q feeds,celery

直接使用

CELERY_ROUTES = {'feed.tasks.import_feed': {'queue': 'feeds'}}
user@z:/$ celery -A proj worker -Q feeds,celery

指定routes,就会自动生成对应的queue,然后使用-Q指定queue启动celery就可以,默认的queue名字是celery。可以看官方文档对默认queue的名字进行修改。

启动多个workers执行不同的任务

在同一台机器上,对于优先级不同的任务最好启动不同的worker去执行,比如把实时任务和定时任务分开,把执行频率高的任务和执行频率低的任务分开,这样有利于保证高优先级的任务可以得到更多的系统资源,同时高频率的实时任务日志比较多也会影响实时任务的日志查看,分开就可以记录到不同的日志文件,方便查看。

$ celery -A proj worker --loglevel=INFO --concurrency=10 -n worker1.%h
$ celery -A proj worker --loglevel=INFO --concurrency=10 -n worker2.%h
$ celery -A proj worker --loglevel=INFO --concurrency=10 -n worker3.%h

可以像这样启动不同的worker,%h可以指定hostname,详细说明可以查看官方文档
高优先级的任务可以分配更多的concurrency,但是并不是worker并法数越多越好,保证任务不堆积就好。

是否需要关注任务执行状态

这个要视具体的业务场景来看,如果对结果不关心,或者任务的执行本身会对数据产生影响,通过对数据的判断可以知道执行的结果那就不需要返回celery任务的退出状态,可以设置

CELERY_IGNORE_RESULT = True

或者

@app.task(ignore_result=True)
def mytask(…):
something()

但是,如果业务需要根据任务执行的状态进行响应的处理就不要这样设置。

内存泄漏

长时间运行Celery有可能发生内存泄露,可以像下面这样设置

CELERYD_MAX_TASKS_PER_CHILD = 40 # 每个worker执行了多少任务就会死掉

使用Celery踩过的坑的更多相关文章

  1. 项目中踩过的坑之-sessionStorage

    总想写点什么,却不知道从何写起,那就从项目中踩过的坑开始吧,希望能给可能碰到相同问题的小伙伴一点帮助. 项目情景: 有一个id,要求通过当前网页打开一个新页面(不是当前页面),并把id传给打开的新页面 ...

  2. web开发实战--弹出式富文本编辑器的实现思路和踩过的坑

    前言: 和弟弟合作, 一起整了个智慧屋的小web站点, 里面包含了很多经典的智力和推理题. 其实该站点从技术层面来分析的话, 也算一个信息发布站点. 因此在该网站的后台运营中, 富文本的编辑器显得尤为 ...

  3. "开发路上踩过的坑要一个个填起来————持续更新······(7月30日)"

    欢迎转载,请注明出处! https://gii16.github.io/learnmore/2016/07/29/problem.html 踩过的坑及解决方案记录在此篇博文中! 个人理解,如有偏颇,欢 ...

  4. 【转载】Fragment 全解析(1):那些年踩过的坑

    http://www.jianshu.com/p/d9143a92ad94 Fragment系列文章:1.Fragment全解析系列(一):那些年踩过的坑2.Fragment全解析系列(二):正确的使 ...

  5. Redis Cluster踩过的坑

    Redis Cluster踩过的坑请参考如下链接:http://www.iteye.com/blogs/subjects/Redis_Cluster_Devops

  6. 第八篇:web之前端踩的一些坑

    前端踩的一些坑   前端踩的一些坑 本节内容 事件代理 清除标签的所有事件 bootstrap的模态框自定义方法 ajax在django里面实现post提交 ajax提交数据嵌套 1.事件代理 之前写 ...

  7. 使用ffmpeg视频编码过程中踩的一个坑

           今天说说使用ffmpeg在写视频编码程序中踩的一个坑,这个坑让我花了好多时间,回头想想,非常多时候一旦思维定势真的挺难突破的.以下是不对的编码结果:                   ...

  8. 那些年踩过的坑之:first-child伪类选择器

    原文:那些年踩过的坑之:first-child伪类选择器 :first-child 选择器用于选取属于其父元素的首个子元素的指定选择器.——w3school 嗯,乍一看好像说的不是很明白,因此这个选择 ...

  9. 《C++之那些年踩过的坑(二)》

    C++之那些年踩过的坑(二) 作者:刘俊延(Alinshans) 本系列文章针对我在写C++代码的过程中,尤其是做自己的项目时,踩过的各种坑.以此作为给自己的警惕. 今天讲一个小点,虽然小,但如果没有 ...

随机推荐

  1. ng-深度学习-课程笔记-9: 机器学习策略1(Week1)

    1 为什么要应用机器学习策略( Why is machine learning strategy ) 当你想优化一个问题的时候,通常可以有很多尝试(比如收集更多数据,增加迭代次数,改用adam,改变网 ...

  2. Spring的一些面试题(转)

    一.spring工作原理: 1.spring mvc的所有请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责对请求进行真正的处理工作.2.DispatcherServlet ...

  3. iptables命令、规则、参数详解

    表    (table)包含4个表:4个表的优先级由高到低:raw-->mangle-->nat-->filterraw---RAW表只使用在PREROUTING链和OUTPUT链上 ...

  4. 20145315 《Java程序设计》第七周学习总结

    20145315 <Java程序设计>第七周学习总结 教材学习内容总结 第十三章 时间与日期 13.1.1时间的度量 1.格林威治时间(GMT):参考太阳到达最高点,有时间误差. 2.世界 ...

  5. 关于Cooperation.GTST

    Cooperation.GTST团队项目简介 我们打算利用Android Studio开发一款博客园的Android APP,初步设想能够实现在Android手机平台使用博客园的相关功能,后续想法会在 ...

  6. ubuntu18.04下挂载网络文件系统失败【学习笔记】

    作者:庄泽彬(欢迎转载,请注明作者) PC:    ubuntu18.04 说明:  之前ubuntu16.04下搭建的环境,开发板挂载网络文件系统是ok的,但是换到ubuntu18.04在启动的时候 ...

  7. Java多线程,线程交替执行

    两个线程,一个打印1-100的奇数,一个打印1-100的偶数:要求:线程1打印5个之后,线程2开始打印,线程2打印5个之后,线程1再开始打印,以此循环. Code: package com.qhong ...

  8. Python学习札记(三十三) 面向对象编程 Object Oriented Program 4

    参考:继承和多态 NOTE 著名的开闭原则: 对扩展开放:允许新增Animal子类: 对修改封闭:不需要修改依赖Animal类型的Animal_func()等函数. 1.eg. #!/usr/bin/ ...

  9. UVa 11889 最小公倍数

    https://vjudge.net/problem/UVA-11889 题意: 输入两个整数A和C,求最小的整数B使得lcm(A,B)=C. 思路: 首先C是A的公倍数,如果C%A不为0肯定是无解的 ...

  10. codevs 2216 行星序列 线段树+延迟标记(BZOJ 1798)

    2216 行星序列  时间限制: 2 s  空间限制: 256000 KB     题目描述 Description “神州“载人飞船的发射成功让小可可非常激动,他立志长大后要成为一名宇航员假期一始, ...