celery和django结合处理异步任务

问题

开发中涉及到一些执行时间长的任务,造成用户等待时间过长影响体验,并发量大的话任务执行也不稳定。

方案

使用celery分布式任务调度框架,生产者将任务先缓存至消息中间件,消费者从中间件获取任务执行;

优势:

            1. 异步提升性能,任务生成和任务执行逻辑分离,降低耦合性,增强用户体验
            2. 数据缓冲,任务上报的速率由用户决定,服务端不可控,此模式可以缓存任务执行速率,达到流量削峰目的,避免引发系统崩溃
            3. 易于扩展,在任务量大时,通过增加任务处理Worker来扩展,提高处理速率

劣势:系统复杂度增加(可以接受)

实施

工具

broker:rabbitmq

backend:redis

操作流程

生产者配置:

django web站点执行任务发布,settings.py配置如下:

from celery import Celery
from kombu import Exchange
# celery配置
APP = Celery()

REDIS_URI = "redis://:%s@%s:%s/%s" % (
    CONFIG_INFO.get("REDIS_PASSWORD"),
    CONFIG_INFO.get("REDIS_HOST"),
    CONFIG_INFO.get("REDIS_PORT"),
    CONFIG_INFO.get("REDIS_DB")
)
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URI,
        'OPTIONS': {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            'MAX_ENTRIES': 1000,
            'CULL_FREQUENCY': 3,
        }
    }
}

APP.conf.update(
    task_serializer='msgpack',  # 任务序列化和反序列化使用msgpack方案
    # result_serializer='json',   # 读取任务结果, 一般性能要求不高,所以使用可读性更好的JSON
    timezone='Asia/Shanghai',  # 指定时区,不指定默认为 'UTC'
    broker_url='amqp://{}:{}@{}:{}'.format(CONFIG_INFO.get('MQ_NAME'), CONFIG_INFO.get('MQ_PASSWORD'),
                                           CONFIG_INFO.get('MQ_URL'), CONFIG_INFO.get('MQ_PORT')),  # broker地址
    result_backend=REDIS_URI  # 存储任务结果
)

# 定义交换机,和消费者保持一致
Exchange('classify', type='topic')

生产者发布任务:

def task_classify(args=None):
    """题目归类任务"""
    task_id = ''  # 任务ID
    args = args or {}
    result = settings.APP.send_task('tasks.classify.classify', (args,), exchange='classify',
                                    routing_key="tasks.classify.classify", eta=None)
    task_id = result.id
    log.info(result)
    return task_id

任务发布后返回任务id,供客户端获取任务执行结果时用

生产者获取任务结果:

def get_task(request):
    """获取指定ID的task"""
    task_id = request.POST.get('task_id', '')
    result = AsyncResult(task_id)
    data = {
        'task_id': result.id,
        'status': result.status,
        'result': result.result
    }
    return ajax_ok(data)

消费者配置:

消费者使用python脚本,通过supervisord部署管理,使用flower查看执行结果

任务执行模块:

up-d9377efdd9a381cb03de87255612e1c59bb.png

关键配置:

# broker地址
broker_url = 'amqp://{}:{}@{}:{}'.format(CONFIG_INFO.get('MQ_NAME'),
                                         CONFIG_INFO.get('MQ_PASSWORD'),
                                         CONFIG_INFO.get('MQ_URL'),
                                         CONFIG_INFO.get('MQ_PORT'))

# 存储任务结果地址
result_backend = f"redis://:{CONFIG_INFO.get('REDIS_PASSWORD')}@{CONFIG_INFO.get('REDIS_HOST')}:" \
                 f"{CONFIG_INFO.get('REDIS_PORT')}/{CONFIG_INFO.get('REDIS_DB')}"

# 创建交换机
default_exchange = Exchange('default', type='topic')
classify_exchange = Exchange('classify', type='topic')  # 归类

# 指定队列
task_queues = (
    Queue('default', exchange=default_exchange, routing_key='*.default.*', delivery_mode=1),
    # 路由键包含“defaul”的消息都进default队列
    Queue('classify', exchange=classify_exchange, routing_key='*.classify.*', delivery_mode=1),
    # 路由键包含“classify”的消息都进classify队列
)

使用supervisord启用消费者和flower服务

[program:celery.worker.zykxcopy]
;celery directory
directory=/code
;运行目录下执行命令,启动worker
command=celery worker -A tasks.classify -Q classify -P gevent -c 8 -l info -n classify_worker

[program:flower]
directory=/code
command=celery flower -A tasks.flower --conf=/code/configs/flowerconfig.py --basic_auth=****:****
wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山水好风光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值