python之celery使用笔记二

初步使用

一般我们使用redis做结果存储,使用rabbitmq做任务队列;

第一步:创建并发送一个异步任务

# 初始化
# tasks.py
from celery import Celery
app = Celery('tasks', broker='amqp://username:passwd@ip:port/varhost',backend='redis://username:passwd@ip:6390/db')

@app.task
def add(x, y):
    return x + y

if __name__ == '__main__':
    result = add.delay(30, 42)

# broker:任务队列的中间人;
# backend:任务执行结果的存储;

发生了什么事

app.task装饰add函数成一个Task实例,add.delay函数将task实例序列化后,通过librabbitmq库的方法将任务发送到rabbitmq;

该过程创建一个名字为celery的exchange交换机,类型为direct(直连交换机);创建一个名为celery的queue,队列和交换机使用路由键celery绑定;

打开rabbitmq管理后台,可以看到有一条消息已经在celery队列中;

记住:当有多个装饰器的时候,app.task一定要在最外层;

扩展

如果使用redis作为任务队列中间人,在redis中存在两个键 celery和_kombu.binding.celery, _kombu.binding.celery表示有一名为 celery 的任务队列(Celery 默认),而键celery为默认队列中的任务列表,使用list类型,可以看看添加进去的任务数据。

第二步:开启worker执行任务
在项目目录下执行命令:

celery -A app.celery_tasks.celery worker -Q queue --loglevel=info

# -A参数指定创建的celery对象的位置,该app.celery_tasks.celery指的是app包下面的celery_tasks.py模块的celery实例,注意一定是初始化后的实例,后面加worker表示该实例就是任务执行者;
# -Q参数指的是该worker接收指定的队列的任务,这是为了当多个队列有不同的任务时可以独立;如果不设会接收所有的队列的任务;
# -l参数指定worker输出的日志级别;

任务执行完毕后结果存储在redis中,查看redis中的数据,发现存在一个string类型的键值对:

celery-task-meta-064e4262-e1ba-4e87-b4a1-52dd1418188f:data

该键值对的失效时间默认为24小时。

分析序列化的消息

add.delay将Task实例序列化后发送到rabbitmq,那么序列化的过程是怎样的呢?

下面是添加到rabbitmq任务队列中的消息数据,使用的是pickle模块对body部分的数据进行序列化:

{"body": "gAJ9cQAoWAQAAAB0YXNrcQFYGAAAAHRlc3RfY2VsZXJ5LmFkZF90b2dldGhlcnECWAIAAABpZHEDWCQAAAA2NmQ1YTg2Yi0xZDM5LTRjODgtYmM5OC0yYzE4YjJjOThhMjFxBFgEAAAAYXJnc3EFSwlLKoZxBlgGAAAAa3dhcmdzcQd9cQhYBwAAAHJldHJpZXNxCUsAWAMAAABldGFxCk5YBwAAAGV4cGlyZXNxC05YAwAAAHV0Y3EMiFgJAAAAY2FsbGJhY2tzcQ1OWAgAAABlcnJiYWNrc3EOTlgJAAAAdGltZWxpbWl0cQ9OToZxEFgHAAAAdGFza3NldHERTlgFAAAAY2hvcmRxEk51Lg==",  
# body是序列化后使用base64编码的信息,包括具体的任务参数,其中包括了需要执行的方法、参数和一些任务基本信息
"content-encoding": "binary", # 序列化数据的编码方式
"content-type": "application/x-python-serialize",  # 任务数据的序列化方式,默认使用python内置的序列化模块pickle
"headers": {}, 
"properties": 
        {"reply_to": "b7580727-07e5-307b-b1d0-4b731a796652",       # 结果的唯一id
        "correlation_id": "66d5a86b-1d39-4c88-bc98-2c18b2c98a21",  # 任务的唯一id
        "delivery_mode": 2, 
        "delivery_info": {"priority": 0, "exchange": "celery", "routing_key": "celery"},  # 指定交换机名称,路由键,属性
        "body_encoding": "base64", # body的编码方式
        "delivery_tag": "bfcfe35d-b65b-4088-bcb5-7a1bb8c9afd9"}}

将序列化消息反序列化
import pickle
import base64
result = base64.b64decode('gAJ9cQAoWAQAAAB0YXNrcQFYGAAAAHRlc3RfY2VsZXJ5LmFkZF90b2dldGhlcnECWAIAAABpZHEDWCQAAAA2NmQ1YTg2Yi0xZDM5LTRjODgtYmM5OC0yYzE4YjJjOThhMjFxBFgEAAAAYXJnc3EFSwlLKoZxBlgGAAAAa3dhcmdzcQd9cQhYBwAAAHJldHJpZXNxCUsAWAMAAABldGFxCk5YBwAAAGV4cGlyZXNxC05YAwAAAHV0Y3EMiFgJAAAAY2FsbGJhY2tzcQ1OWAgAAABlcnJiYWNrc3EOTlgJAAAAdGltZWxpbWl0cQ9OToZxEFgHAAAAdGFza3NldHERTlgFAAAAY2hvcmRxEk51Lg==')
print(pickle.loads(result))

# 结果
{
    'task': 'test_celery.add_together',  # 需要执行的任务
    'id': '66d5a86b-1d39-4c88-bc98-2c18b2c98a21',  # 任务的唯一id
    'args': (9, 42),   # 任务的参数
    'kwargs': {},      
    'retries': 0, 
    'eta': None, 
    'expires': None, # 任务失效时间
    'utc': True, 
    'callbacks': None, # 完成后的回调
    'errbacks': None,  # 任务失败后的回调
    'timelimit': (None, None), # 超时时间
    'taskset': None, 
    'chord': None
}

我们可以看到body里面有我们需要执行的函数的一切信息,celery的worker接收到消息后就会反序列化body数据,执行相应的方法。

常见的数据序列化方式

binary: 二进制序列化方式;python的pickle默认的序列化方法;
json:json 支持多种语言, 可用于跨语言方案,但好像不支持自定义的类对象;
XML:类似标签语言;
msgpack:二进制的类 json 序列化方案, 但比 json 的数据结构更小, 更快;
yaml:yaml 表达能力更强, 支持的数据类型较 json 多, 但是 python 客户端的性能不如 json
经过比较,为了保持跨语言的兼容性和速度,采用msgpack或json方式;

celery配置

celery的性能和许多因素有关,比如序列化的方式,连接rabbitmq的方式,多进程、单线程等等,我们可以指定配置;

基本配置项

CELERY_DEFAULT_QUEUE:默认队列
BROKER_URL  : 代理人即rabbitmq的网址
CELERY_RESULT_BACKEND:结果存储地址
CELERY_TASK_SERIALIZER:任务序列化方式
CELERY_RESULT_SERIALIZER:任务执行结果序列化方式
CELERY_TASK_RESULT_EXPIRES:任务过期时间
CELERY_ACCEPT_CONTENT:指定任务接受的内容序列化类型(序列化),一个列表;

加载配置

# main.py
from celery import Celery
import celeryconfig
app = Celery(__name__, include=["task"])
# 引入配置文件
app.config_from_object(celeryconfig)

if __name__ == '__main__':
    result = add.delay(30, 42)

task.py

from main import app
@app.task
def add(x, y):
    return x + y  

celeryconfig.py

BROKER_URL =  'amqp://username:password@localhost:5672/yourvhost'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_TASK_SERIALIZER = 'msgpack'
CELERY_RESULT_SERIALIZER = 'msgpack'
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24   # 任务过期时间
CELERY_ACCEPT_CONTENT = ["msgpack"]            # 指定任务接受的内容序列化的类型.

from celery import Celery
import celeryconfig
app = Celery(__name__, include=["task"])
app.conf.update(
        task_serializer='json',
        accept_content=['json'],
        result_serializer='json',
        timezone='Europe/Oslo',
        enable_utc=True,
    )

也可以直接加载配置,此外还有两个方法可以加载配置,但开发不会直接调用:

app.config_from_envvar() # 从环境变量加载
app.config_from_cmdline() # 从命令行加载

一份比较常用的配置文件

# 注意,celery4版本后,CELERY_BROKER_URL改为BROKER_URL
BROKER_URL = 'amqp://username:passwd@host:port/虚拟主机名'
# 指定结果的接受地址
CELERY_RESULT_BACKEND = 'redis://username:passwd@host:port/db'
# 指定任务序列化方式
CELERY_TASK_SERIALIZER = 'msgpack' 
# 指定结果序列化方式
CELERY_RESULT_SERIALIZER = 'msgpack'
# 任务过期时间,celery任务执行结果的超时时间
CELERY_TASK_RESULT_EXPIRES = 60 * 20   
# 指定任务接受的序列化类型.
CELERY_ACCEPT_CONTENT = ["msgpack"]   
# 任务发送完成是否需要确认,这一项对性能有一点影响     
CELERY_ACKS_LATE = True  
# 压缩方案选择,可以是zlib, bzip2,默认是发送没有压缩的数据
CELERY_MESSAGE_COMPRESSION = 'zlib' 
# 规定完成任务的时间
CELERYD_TASK_TIME_LIMIT = 5  # 在5s内完成任务,否则执行该任务的worker将被杀死,任务移交给父进程
# celery worker的并发数,默认是服务器的内核数目,也是命令行-c参数指定的数目
CELERYD_CONCURRENCY = 4 
# celery worker 每次去rabbitmq预取任务的数量
CELERYD_PREFETCH_MULTIPLIER = 4 
# 每个worker执行了多少任务就会死掉,默认是无限的
CELERYD_MAX_TASKS_PER_CHILD = 40 
# 设置默认的队列名称,如果一个消息不符合其他的队列就会放在默认队列里面,如果什么都不设置的话,数据都会发送到默认的队列中
CELERY_DEFAULT_QUEUE = "default" 
# 设置详细的队列
CELERY_QUEUES = {
    "default": { # 这是上面指定的默认队列
        "exchange": "default",
        "exchange_type": "direct",
        "routing_key": "default"
    },
    "topicqueue": { # 这是一个topic队列 凡是topictest开头的routing key都会被放到这个队列
        "routing_key": "topic.#",
        "exchange": "topic_exchange",
        "exchange_type": "topic",
    },
    "task_eeg": { # 设置扇形交换机
        "exchange": "tasks",
        "exchange_type": "fanout",
        "binding_key": "tasks",
    },
}

在celery4.0以后配置参数改成了小写,对于4.0以后的版本替代参数:

4.0版本以下参数          4.0版本以上配置参数
CELERY_ACCEPT_CONTENT   accept_content
CELERY_ENABLE_UTC   enable_utc
CELERY_IMPORTS  imports
CELERY_INCLUDE  include
CELERY_TIMEZONE timezone
CELERYBEAT_MAX_LOOP_INTERVAL    beat_max_loop_interval
CELERYBEAT_SCHEDULE beat_schedule
CELERYBEAT_SCHEDULER    beat_scheduler
CELERYBEAT_SCHEDULE_FILENAME    beat_schedule_filename
CELERYBEAT_SYNC_EVERY   beat_sync_every
BROKER_URL  broker_url
BROKER_TRANSPORT    broker_transport
BROKER_TRANSPORT_OPTIONS    broker_transport_options
BROKER_CONNECTION_TIMEOUT   broker_connection_timeout
BROKER_CONNECTION_RETRY broker_connection_retry
BROKER_CONNECTION_MAX_RETRIES   broker_connection_max_retries
BROKER_FAILOVER_STRATEGY    broker_failover_strategy
BROKER_HEARTBEAT    broker_heartbeat
BROKER_LOGIN_METHOD broker_login_method
BROKER_POOL_LIMIT   broker_pool_limit
BROKER_USE_SSL  broker_use_ssl
CELERY_CACHE_BACKEND    cache_backend
CELERY_CACHE_BACKEND_OPTIONS    cache_backend_options
CASSANDRA_COLUMN_FAMILY cassandra_table
CASSANDRA_ENTRY_TTL cassandra_entry_ttl
CASSANDRA_KEYSPACE  cassandra_keyspace
CASSANDRA_PORT  cassandra_port
CASSANDRA_READ_CONSISTENCY  cassandra_read_consistency
CASSANDRA_SERVERS   cassandra_servers
CASSANDRA_WRITE_CONSISTENCY cassandra_write_consistency
CASSANDRA_OPTIONS   cassandra_options
CELERY_COUCHBASE_BACKEND_SETTINGS   couchbase_backend_settings
CELERY_MONGODB_BACKEND_SETTINGS mongodb_backend_settings
CELERY_EVENT_QUEUE_EXPIRES  event_queue_expires
CELERY_EVENT_QUEUE_TTL  event_queue_ttl
CELERY_EVENT_QUEUE_PREFIX   event_queue_prefix
CELERY_EVENT_SERIALIZER event_serializer
CELERY_REDIS_DB redis_db
CELERY_REDIS_HOST   redis_host
CELERY_REDIS_MAX_CONNECTIONS    redis_max_connections
CELERY_REDIS_PASSWORD   redis_password
CELERY_REDIS_PORT   redis_port
CELERY_RESULT_BACKEND   result_backend
CELERY_MAX_CACHED_RESULTS   result_cache_max
CELERY_MESSAGE_COMPRESSION  result_compression
CELERY_RESULT_EXCHANGE  result_exchange
CELERY_RESULT_EXCHANGE_TYPE result_exchange_type
CELERY_TASK_RESULT_EXPIRES  result_expires
CELERY_RESULT_PERSISTENT    result_persistent
CELERY_RESULT_SERIALIZER    result_serializer
CELERY_RESULT_DBURI 请result_backend改用。
CELERY_RESULT_ENGINE_OPTIONS    database_engine_options
[...]_DB_SHORT_LIVED_SESSIONS   database_short_lived_sessions
CELERY_RESULT_DB_TABLE_NAMES    database_db_names
CELERY_SECURITY_CERTIFICATE security_certificate
CELERY_SECURITY_CERT_STORE  security_cert_store
CELERY_SECURITY_KEY security_key
CELERY_ACKS_LATE    task_acks_late
CELERY_TASK_ALWAYS_EAGER    task_always_eager
CELERY_TASK_ANNOTATIONS task_annotations
CELERY_TASK_COMPRESSION task_compression
CELERY_TASK_CREATE_MISSING_QUEUES   task_create_missing_queues
CELERY_TASK_DEFAULT_DELIVERY_MODE   task_default_delivery_mode
CELERY_TASK_DEFAULT_EXCHANGE    task_default_exchange
CELERY_TASK_DEFAULT_EXCHANGE_TYPE   task_default_exchange_type
CELERY_TASK_DEFAULT_QUEUE   task_default_queue
CELERY_TASK_DEFAULT_RATE_LIMIT  task_default_rate_limit
CELERY_TASK_DEFAULT_ROUTING_KEY task_default_routing_key
CELERY_TASK_EAGER_PROPAGATES    task_eager_propagates
CELERY_TASK_IGNORE_RESULT   task_ignore_result
CELERY_TASK_PUBLISH_RETRY   task_publish_retry
CELERY_TASK_PUBLISH_RETRY_POLICY    task_publish_retry_policy
CELERY_QUEUES   task_queues
CELERY_ROUTES   task_routes
CELERY_TASK_SEND_SENT_EVENT task_send_sent_event
CELERY_TASK_SERIALIZER  task_serializer
CELERYD_TASK_SOFT_TIME_LIMIT    task_soft_time_limit
CELERYD_TASK_TIME_LIMIT task_time_limit
CELERY_TRACK_STARTED    task_track_started
CELERYD_AGENT   worker_agent
CELERYD_AUTOSCALER  worker_autoscaler
CELERYD_CONCURRENCY worker_concurrency
CELERYD_CONSUMER    worker_consumer
CELERY_WORKER_DIRECT    worker_direct
CELERY_DISABLE_RATE_LIMITS  worker_disable_rate_limits
CELERY_ENABLE_REMOTE_CONTROL    worker_enable_remote_control
CELERYD_HIJACK_ROOT_LOGGER  worker_hijack_root_logger
CELERYD_LOG_COLOR   worker_log_color
CELERYD_LOG_FORMAT  worker_log_format
CELERYD_WORKER_LOST_WAIT    worker_lost_wait
CELERYD_MAX_TASKS_PER_CHILD worker_max_tasks_per_child
CELERYD_POOL    worker_pool
CELERYD_POOL_PUTLOCKS   worker_pool_putlocks
CELERYD_POOL_RESTARTS   worker_pool_restarts
CELERYD_PREFETCH_MULTIPLIER worker_prefetch_multiplier
CELERYD_REDIRECT_STDOUTS    worker_redirect_stdouts
CELERYD_REDIRECT_STDOUTS_LEVEL  worker_redirect_stdouts_level
CELERYD_SEND_EVENTS worker_send_task_events
CELERYD_STATE_DB    worker_state_db
CELERYD_TASK_LOG_FORMAT worker_task_log_format
CELERYD_TIMER   worker_timer
CELERYD_TIMER_PRECISION worker_timer_precision
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容