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

from celery import task
from celery.five import monotonic
from celery.utils.log import get_task_logger
from contextlib import contextmanager
from django.core.cache import cache
from hashlib import md5
from djangofeeds.models import Feed logger = get_task_logger(__name__) LOCK_EXPIRE = 60 * 10 # Lock expires in 10 minutes @contextmanager
def memcache_lock(lock_id, oid):
timeout_at = monotonic() + LOCK_EXPIRE - 3
# cache.add fails if the key already exists
status = cache.add(lock_id, oid, LOCK_EXPIRE)
try:
yield status
finally:
# memcache delete is very slow, but we have to use it to take
# advantage of using add() for atomic locking
if monotonic() < timeout_at and status:
# don't release the lock if we exceeded the timeout
# to lessen the chance of releasing an expired lock
# owned by someone else
# also don't release the lock if we didn't acquire it
cache.delete(lock_id) @task(bind=True)
def import_feed(self, feed_url):
# The cache key consists of the task name and the MD5 digest
# of the feed URL.
feed_url_hexdigest = md5(feed_url).hexdigest()
lock_id = '{0}-lock-{1}'.format(self.name, feed_url_hexdigest)
logger.debug('Importing feed: %s', feed_url)
with memcache_lock(lock_id, self.app.oid) as acquired:
if acquired:
return Feed.objects.import_feed(feed_url).url
logger.debug(
'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的多节点配置实例,由于资源限制只找了两台机器做测试

10.10.42.33
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配置文件:
cat celeryconfig.py
#!/usr/bin/python
#coding:utf-8
from kombu import Queue
CELERY_TIMEZONE = 'Asia/Shanghai'
####################################
# 一般配置 #
####################################
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_ACCEPT_CONTENT=['json']
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = True
# List of modules to import when celery starts.
CELERY_IMPORTS = ('tasks', )
CELERYD_MAX_TASKS_PER_CHILD = 40 # 每个worker执行了多少任务就会死掉
BROKER_POOL_LIMIT = 10 #默认celery与broker连接池连接数
CELERY_DEFAULT_QUEUE='default'
CELERY_DEFAULT_ROUTING_KEY='task.default'
CELERY_RESULT_BACKEND='redis://:fafafa@10.10.190.234:6379/0'
BROKER_URL='redis://:fafafa@10.19.190.234:6379/0'
#默认队列
CELERY_DEFAULT_QUEUE = 'celery' #定义默认队列
CELERY_DEFAULT_ROUTING_KEY = 'celery' #定义默认路由
CELERYD_LOG_FILE="./logs/celery.log"
CELERY_QUEUES = (
Queue("queue_add", routing_key='queue_add'),
Queue('queue_reduce', routing_key='queue_sum'),
Queue('celery', routing_key='celery'),
)
CELERY_ROUTES = {
'task.add':{'queue':'queue_add', 'routing_key':'queue_add'},
'task.reduce':{'queue':'queue_reduce', 'routing_key':'queue_sum'},
} 
查看任务配置文件:

  cat task.py

import os
import sys
import datetime
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from celery import Celery
from celery import chain, group, chord, Task
from celeryservice import celeryconfig
app = Celery()
app.config_from_object(celeryconfig)
__all__ = ['add', 'reduce','sum_all', 'other']
####################################
# task定义 #
####################################
@app.task
def add(x, y):
return x + y
@app.task
def reduce(x, y):
return x - y
@app.task
def sum(values):
return sum([int(value) for value in values])
@app.task
def other(x, y):
return x * y

  

flower任务配置文件

  cat flower.py

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

启动服务:

  在33上启动服务

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

  在234上启动服务

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临时服务或者网络出现问题,没准马上就好了,那么为什么不试着加个重试测试一下呢?

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

  

定时任务遇到的问题:

  

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

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

# -*- coding:utf-8 -*-
from datetime import timedelta
from settings import REDIS_HOST, REDIS_PORT, REDIS_PASSWORD, REDIS_DB_NUM # 某个程序中出现的队列,在broker中不存在,则立刻创建它
CELERY_CREATE_MISSING_QUEUES = True CELERY_IMPORTS = ("async_task.tasks", "async_task.notify") # 使用redis 作为任务队列
BROKER_URL = 'redis://:' + REDIS_PASSWORD + '@' + REDIS_HOST + ':' + str(REDIS_PORT) + '/' + str(REDIS_DB_NUM) #CELERY_RESULT_BACKEND = 'redis://:' + REDIS_PASSWORD + '@' + REDIS_HOST + ':' + str(REDIS_PORT) + '/10' CELERYD_CONCURRENCY = 20 # 并发worker数 CELERY_TIMEZONE = 'Asia/Shanghai' CELERYD_FORCE_EXECV = True # 非常重要,有些情况下可以防止死锁 CELERYD_PREFETCH_MULTIPLIER = 1 CELERYD_MAX_TASKS_PER_CHILD = 100 # 每个worker最多执行万100个任务就会被销毁,可防止内存泄露
# CELERYD_TASK_TIME_LIMIT = 60 # 单个任务的运行时间不超过此值,否则会被SIGKILL 信号杀死
# BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 90}
# 任务发出后,经过一段时间还未收到acknowledge , 就将任务重新交给其他worker执行
CELERY_DISABLE_RATE_LIMITS = True # 定时任务
CELERYBEAT_SCHEDULE = {
'msg_notify': {
'task': 'async_task.notify.msg_notify',
'schedule': timedelta(seconds=10),
#'args': (redis_db),
'options' : {'queue':'my_period_task'}
},
'report_result': {
'task': 'async_task.tasks.report_result',
'schedule': timedelta(seconds=10),
#'args': (redis_db),
'options' : {'queue':'my_period_task'}
},
#'report_retry': {
# 'task': 'async_task.tasks.report_retry',
# 'schedule': timedelta(seconds=60),
# 'options' : {'queue':'my_period_task'}
#}, }
################################################
# 启动worker的命令
# *** 定时器 ***
# nohup celery beat -s /var/log/boas/celerybeat-schedule --logfile=/var/log/boas/celerybeat.log -l info &
# *** worker ***
# 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. Django restframe 视图函数以及ModelSerializer的使用

    建立model数据库 from django.db import models __all__ = ['Book', 'Publisher', 'Author'] # Create your mode ...

  2. HTML5-SVG-基础篇

    什么是SVG? SVG 指可伸缩矢量图形 (Scalable Vector Graphics) SVG 用于定义用于网络的基于矢量的图形 SVG 使用 XML 格式定义图形 SVG 图像在放大或改变尺 ...

  3. 记一次Java调优案例分析

    上周,一同学给我发来,他们那里的案例 一看就是新生代产生过多对象,肯定是批量或者循环操作导致的,导致新生代一直在进行回收导致. 如果是老生代出现这样的问题,大部分情况下是列表或者集合导致的. 因此我们 ...

  4. 贝叶斯定理推导(Bayes' Theorem Induction)

    这里用Venn diagram来不严谨地推导一下贝叶斯定理. 假设A和B为两个不相互独立的事件. 交集(intersection):  上图红色部分即为事件A和事件B的交集. 并集(union):  ...

  5. eclipse 保存html 提示 save could not be completed

    重启ecplise 即可

  6. SPOJ divcntk(min25筛)

    题意 \(\sigma_0(i)\) 表示 \(i\) 的约数个数 求 \[ S_k(n)=\sum_{i=1}^n\sigma_0(i^k)\pmod {2^{64}} \] 共 \(T\) 组数据 ...

  7. 【Luogu3731】[HAOI2017]新型城市化(网络流,Tarjan)

    [Luogu3731][HAOI2017]新型城市化(网络流,Tarjan) 题面 洛谷 给定一张反图,保证原图能分成不超过两个团,问有多少种加上一条边的方法,使得最大团的个数至少加上\(1\). 题 ...

  8. 【BZOJ5317】[JSOI2018]部落战争(凸包,闵可夫斯基和)

    [BZOJ5317][JSOI2018]部落战争(凸包,闵可夫斯基和) 题面 BZOJ 洛谷 题解 很明显我们只需要两个凸包\(A,B\). 假设询问给定的方向向量是\(v\). 那么现在就是判断\( ...

  9. 配置日志中显示IP

    package com.demo.conf; import ch.qos.logback.classic.pattern.ClassicConverter; import ch.qos.logback ...

  10. [ZJOI2015]地震后的幻想乡(期望+dp)

    题目描述 傲娇少女幽香是一个很萌很萌的妹子,而且她非常非常地有爱心,很喜欢为幻想乡的人们做一些自己力所能及的事情来帮助他们. 这不,幻想乡突然发生了地震,所有的道路都崩塌了.现在的首要任务是尽快让幻想 ...