确保任务不重叠解决方法:

  1. from celery import task
  2. from celery.five import monotonic
  3. from celery.utils.log import get_task_logger
  4. from contextlib import contextmanager
  5. from django.core.cache import cache
  6. from hashlib import md5
  7. from djangofeeds.models import Feed
  8.  
  9. logger = get_task_logger(__name__)
  10.  
  11. LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes
  12.  
  13. @contextmanager
  14. def memcache_lock(lock_id, oid):
  15. timeout_at = monotonic() + LOCK_EXPIRE - 3
  16. # cache.add fails if the key already exists
  17. status = cache.add(lock_id, oid, LOCK_EXPIRE)
  18. try:
  19. yield status
  20. finally:
  21. # memcache delete is very slow, but we have to use it to take
  22. # advantage of using add() for atomic locking
  23. if monotonic() < timeout_at and status:
  24. # don't release the lock if we exceeded the timeout
  25. # to lessen the chance of releasing an expired lock
  26. # owned by someone else
  27. # also don't release the lock if we didn't acquire it
  28. cache.delete(lock_id)
  29.  
  30. @task(bind=True)
  31. def import_feed(self, feed_url):
  32. # The cache key consists of the task name and the MD5 digest
  33. # of the feed URL.
  34. feed_url_hexdigest = md5(feed_url).hexdigest()
  35. lock_id = '{0}-lock-{1}'.format(self.name, feed_url_hexdigest)
  36. logger.debug('Importing feed: %s', feed_url)
  37. with memcache_lock(lock_id, self.app.oid) as acquired:
  38. if acquired:
  39. return Feed.objects.import_feed(feed_url).url
  40. logger.debug(
  41. 'Feed %s is already being imported by another worker', feed_url)

celery 特性:

  Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。由于在工作的平台中用到Celery系统(用于发送邮件、发送短信、发送上线等任务),记录一下学习的知识。

使用rabbitmq做celery的broker和redis做celery的broker的特性

使用RabbitMQ作为Celery Broker的优点:
         Highly customizable routing(高度定制路由)
         Persistent queues(一致性队列)

使用redis作为celery brocker的优点:
        high speed due to in memory datastore(速度极快的内存数据库)
        can double up as both key-value datastore and job queue(可以保证key-value 数据存储及job序列)

celery-安装

  pip3 install celery(4.0版本celery beat不支持热加载)

celery-flower监控安装

  pip3 install flower

django  celery 安装

  pip3 install django-celery

celery 原理介绍

某个方法的消息请求celery执行,首先celery根据绑定的规则把任务消息放到制定的路由队列中去,此队列对应的worker节点取出执行。

说明:
      为什么要定义多个worker?每个worker都会新建一个进程,充分利用服务器资源,提高执行效率。
      同一个服务器可以启动多个worker节点?可以,启动参数里面写上不同的–hostname即可。
      celery默认会创建一个celery任务队列,没有任何绑定的任务将会发送到此消息队列中。

celery 多woker实验

celery加redis的多节点配置实例,由于资源限制只找了两台机器做测试

  1. 10.10.42.33
  2. 10.10.190.234

  我们把redis服务放在10.10.190.234那台服务器上
  我们把flower服务也启动在10.10.42.33那台服务器上
  代码中定义的队列有queue_add、queue_sum (还有个默认队列celery)
  33、234服务器用于启动worker节点
  33服务器上启动处理celery和queue_add队列的worker节点
  234服务器上启动处理celery和queue_sum队列的worker节点

配置文件展示

  celeryconfig配置文件:
  1. cat celeryconfig.py
  2. #!/usr/bin/python
  3. #coding:utf-8
  4. from kombu import Queue
  5. CELERY_TIMEZONE = 'Asia/Shanghai'
  6. ####################################
  7. # 一般配置 #
  8. ####################################
  9. CELERY_TASK_SERIALIZER = 'json'
  10. CELERY_RESULT_SERIALIZER = 'json'
  11. CELERY_ACCEPT_CONTENT=['json']
  12. CELERY_TIMEZONE = 'Asia/Shanghai'
  13. CELERY_ENABLE_UTC = True
  14. # List of modules to import when celery starts.
  15. CELERY_IMPORTS = ('tasks', )
  16. CELERYD_MAX_TASKS_PER_CHILD = 40 # 每个worker执行了多少任务就会死掉
  17. BROKER_POOL_LIMIT = 10 #默认celery与broker连接池连接数
  18. CELERY_DEFAULT_QUEUE='default'
  19. CELERY_DEFAULT_ROUTING_KEY='task.default'
  20. CELERY_RESULT_BACKEND='redis://:fafafa@10.10.190.234:6379/0'
  21. BROKER_URL='redis://:fafafa@10.19.190.234:6379/0'
  22. #默认队列
  23. CELERY_DEFAULT_QUEUE = 'celery' #定义默认队列
  24. CELERY_DEFAULT_ROUTING_KEY = 'celery' #定义默认路由
  25. CELERYD_LOG_FILE="./logs/celery.log"
  26. CELERY_QUEUES = (
  27. Queue("queue_add", routing_key='queue_add'),
  28. Queue('queue_reduce', routing_key='queue_sum'),
  29. Queue('celery', routing_key='celery'),
  30. )
  31. CELERY_ROUTES = {
  32. 'task.add':{'queue':'queue_add', 'routing_key':'queue_add'},
  33. 'task.reduce':{'queue':'queue_reduce', 'routing_key':'queue_sum'},
  34. } 
查看任务配置文件:

  cat task.py

  1. import os
  2. import sys
  3. import datetime
  4. BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  5. sys.path.append(BASE_DIR)
  6. from celery import Celery
  7. from celery import chain, group, chord, Task
  8. from celeryservice import celeryconfig
  9. app = Celery()
  10. app.config_from_object(celeryconfig)
  11. __all__ = ['add', 'reduce','sum_all', 'other']
  12. ####################################
  13. # task定义 #
  14. ####################################
  15. @app.task
  16. def add(x, y):
  17. return x + y
  18. @app.task
  19. def reduce(x, y):
  20. return x - y
  21. @app.task
  22. def sum(values):
  23. return sum([int(value) for value in values])
  24. @app.task
  25. def other(x, y):
  26. return x * y

  

flower任务配置文件

  cat flower.py

  1. #!/usr/bin/env python
  2. #coding:utf-8
  3. broker_api = 'redis://:afafafafa@10.10.190.234:6379/0'
  4. logging = 'DEBUG'
  5. address = '0.0.0.0'
  6. port = 5555
  7. basic_auth = ['zero:zero'] #外部访问密码
  8. persistent=True #持久化celery tasks(如果为false的话,重启flower之后,监控的task就消失了)
  9. db="./flower/flower_db"

启动服务:

  在33上启动服务

  1. celery worker -A task --loglevel=info --queues=celery,queue_add --hostname=celery_worker33 >/dev/null 2>&1 &

  在234上启动服务

  1. celery worker -A task --loglevel=info --queues=celery,queue_add --hostname=celery_worker33 >/dev/null 2>&1 &

服务验证:

  在任一台有celeryservice项目代码的服务器上,运行add、reduce、sum、other任务(测试可简单使用add.delay(1,2)等)
  add只会在33上运行,
  sum任务,可能会在33或234服务器的worker节点运行
  reduce任务,只会在234上运行。
  other任务可能会在33或者234上运行。

关于使用过程中的优化

使用celery的错误处理机制

  如下内容来自于网站,还没实践,存档用。
  大多数任务并没有使用错误处理,如果任务失败,那就失败了。在一些情况下这很不错,但是作者见到的多数失败任务都是去调用第三方API然后出现了网络错误,
  或者资源不可用这些错误,而对于这些错误,最简单的方式就是重试一下,也许就是第三方API临时服务或者网络出现问题,没准马上就好了,那么为什么不试着加个重试测试一下呢?

  1. @app.task(bind=True, default_retry_delay=300, max_retries=5)
  2. def my_task_A():
  3. try:
  4. print("doing stuff here...")
  5. except SomeNetworkException as e:
  6. print("maybe do some clenup here....")
  7. self.retry(e)

  

定时任务遇到的问题:

  

  通过flower 查看 跑多线程报错, 需要减少线程数.

celery配置文件的一些详细解释:

  1. # -*- coding:utf-8 -*-
  2. from datetime import timedelta
  3. from settings import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB_NUM
  4.  
  5. # 某个程序中出现的队列,在broker中不存在,则立刻创建它
  6. CELERY_CREATE_MISSING_QUEUES = True
  7.  
  8. CELERY_IMPORTS = ("async_task.tasks", "async_task.notify")
  9.  
  10. # 使用redis 作为任务队列
  11. BROKER_URL = 'redis://:' + REDIS_PASSWORD + '@' + REDIS_HOST + ':' + str(REDIS_PORT) + '/' + str(REDIS_DB_NUM)
  12.  
  13. #CELERY_RESULT_BACKEND = 'redis://:' + REDIS_PASSWORD + '@' + REDIS_HOST + ':' + str(REDIS_PORT) + '/10'
  14.  
  15. CELERYD_CONCURRENCY = 20 # 并发worker数
  16.  
  17. CELERY_TIMEZONE = 'Asia/Shanghai'
  18.  
  19. CELERYD_FORCE_EXECV = True # 非常重要,有些情况下可以防止死锁
  20.  
  21. CELERYD_PREFETCH_MULTIPLIER = 1
  22.  
  23. CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行万100个任务就会被销毁,可防止内存泄露
  24. # CELERYD_TASK_TIME_LIMIT = 60 # 单个任务的运行时间不超过此值,否则会被SIGKILL 信号杀死
  25. # BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 90}
  26. # 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行
  27. CELERY_DISABLE_RATE_LIMITS = True
  28.  
  29. # 定时任务
  30. CELERYBEAT_SCHEDULE = {
  31. 'msg_notify': {
  32. 'task': 'async_task.notify.msg_notify',
  33. 'schedule': timedelta(seconds=10),
  34. #'args': (redis_db),
  35. 'options' : {'queue':'my_period_task'}
  36. },
  37. 'report_result': {
  38. 'task': 'async_task.tasks.report_result',
  39. 'schedule': timedelta(seconds=10),
  40. #'args': (redis_db),
  41. 'options' : {'queue':'my_period_task'}
  42. },
  43. #'report_retry': {
  44. # 'task': 'async_task.tasks.report_retry',
  45. # 'schedule': timedelta(seconds=60),
  46. # 'options' : {'queue':'my_period_task'}
  47. #},
  48.  
  49. }
  50. ################################################
  51. # 启动worker的命令
  52. # *** 定时器 ***
  53. # nohup celery beat -s /var/log/boas/celerybeat-schedule --logfile=/var/log/boas/celerybeat.log -l info &
  54. # *** worker ***
  55. # nohup celery worker -f /var/log/boas/boas_celery.log -l INFO &

celery整体架构图:

  

定时任务调度-Celery的更多相关文章

  1. python中的轻量级定时任务调度库:schedule

    提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中.不过,一个小的定时脚本,要用celery的话太“重”了.所以,我找到了一个轻量级的定时任务调度的库:sch ...

  2. 11: python中的轻量级定时任务调度库:schedule

    1.1 schedule 基本使用 1.schedule 介绍 1. 提到定时任务调度的时候,相信很多人会想到芹菜celery,要么就写个脚本塞到crontab中. 2. 不过,一个小的定时脚本,要用 ...

  3. [源码分析] 定时任务调度框架 Quartz 之 故障切换

    [源码分析] 定时任务调度框架 Quartz 之 故障切换 目录 [源码分析] 定时任务调度框架 Quartz 之 故障切换 0x00 摘要 0x01 基础概念 1.1 分布式 1.1.1 功能方面 ...

  4. #研发中间件介绍#定时任务调度与管理JobCenter

    郑昀 最后更新于2014/11/11 关键词:定时任务.调度.监控报警.Job.crontab.Java 本文档适用人员:研发员工   没有JobCenter时我们要面对的:   电商业务链条很长,业 ...

  5. Java定时任务调度详解

    前言 在实际项目开发中,除了Web应用.SOA服务外,还有一类不可缺少的,那就是定时任务调度.定时任务的场景可以说非常广泛,比如某些视频网站,购买会员后,每天会给会员送成长值,每月会给会员送一些电影券 ...

  6. Spring4.0.1+Quartz2.2.1实现定时任务调度[亲测可用]

    Spring4.0.1+Quartz2.2.1实现定时任务调度[亲测可用] tip:只需要配置xml文件即可 1.第三方依赖包的引入 <properties> <project.bu ...

  7. SpringQuartz 实现定时任务调度

    最近公司新项目需要用到定时器,于是研究了一下发现: Spring中使用Quartz有两种方式实现: 第一种是任务类继承QuartzJobBean 第二种则是在配置文件里定义任务类和要执行的方法,类和方 ...

  8. 开源一个定时任务调度器 webscheduler

    在企业应用中定时任务调度的需求是必不可少的,比如定时同步数据,定时结转数据,定时检测异常等等.公司之前是在使用一款采用.net 开发的windows服务形式的定时程序,基本能满足需求,在一段时间的时候 ...

  9. 一文揭秘定时任务调度框架quartz

    之前写过quartz或者引用过quartz的一些文章,有很多人给我发消息问quartz的相关问题, quartz 报错:java.lang.classNotFoundException quartz源 ...

随机推荐

  1. Vuex的API文档

    前面的话 本文将详细介绍Vuex的API文档 概述 import Vuex from 'vuex' const store = new Vuex.Store({ ...options }) [构造器选 ...

  2. 排列组合n选m算法

    找10组合算法,非递归 http://blog.csdn.net/sdhongjun/article/details/51475302

  3. Nintex Workflow Get Attachment link

    不多解释,直接上图,操作简单

  4. 前端传递给后端且通过cookie方式,尽量传递id

    前端传递给后端且通过cookie方式,尽量传递id

  5. 醉汉随机行走/随机漫步问题(Random Walk Randomized Algorithm Python)

    世界上有些问题看似是随机的(stochastic),没有规律可循,但很可能是人类还未发现和掌握这类事件的规律,所以说它们是随机发生的. 随机漫步(Random  Walk)是一种解决随机问题的方法,它 ...

  6. 【支付宝】"验签出错,sign值与sign_type参数指定的签名类型不一致:sign_type参数值为RSA,您实际用的签名类型可能是RSA2"

    问题定位:从描述就可以看的出来了,你现在sign_type是  RSA类型的,要改成跟你现在用的签名类型一致的类型,也就是 要改为 RSA2 PHP为例 // 新版只支持此种签名方式 商户生成签名字符 ...

  7. Android studio preview界面无法预览,报错render problem

    1.查看报错信息,如果有报错,该叹号应为红色,点击查看报错,显示为render problem 2.打开res/styles.xml修改为如图,添加Base. 3.再打开preview界面

  8. Android里透明的ListView

    发现了一个list滚动时,某item背景透明的问题.网上搜索一下,发现有很多人在问list背景黑色的问题,交流中给出的解决方案基本上很统一. 先是解释问题产生的原因是Android对list的滚动做了 ...

  9. [CF1107E]Vasya and Binary String【区间DP】

    题目描述 Vasya has a string s of length n consisting only of digits 0 and 1. Also he has an array a of l ...

  10. visual studio 阅读 linux-kernel

    @2018-12-13 [小记] 使用 visual studio 阅读 linux-kernel 方法 a. 文件 ---> 新建 --->从现有代码创建项目 b. 指定项目存储位置,命 ...