luffy项目之django操作redis,celery使用

luffy项目之django操作redis,celery使用

复习

# redis:非关系型数据库,存数据的地方,纯内存操作,6.x之前 单线程架构,5大数据类型
# 编译安装,win支持不好
# 启动服务:redis-server 配置文件     使用win的服务启动
# 停止服务: shutdown                 使用win的服务停止
# 客户端链接:redis-cli -h 地址 -p 端口   

# python链接redis,连接池链接(把池做成单例)单例:整个全局就这一个实例 实现了全局只用这一个实例
# 字符串操作:get set      
# 字典操作:hget  hset      5大数据类型,只支持一层,后面都是字符串
	hash1    hobby   ['篮球','足球']  # 把value转成json格式字符串存入
# 列表操作:lpush  lpop  blpop
# 通用操作

1 djagno 使用redis

1.1 通用操作(跟框架无关)

# 写一个py文件
import redis

POOL = redis.ConnectionPool(host='127.0.0.1', port=6379, max_connections=100)

# 导入,使用
from utils.redis_pool import POOL
import redis
conn=redis.Redis(connection_pool=POOL)
conn.set('name','lqz')
conn.close()

1.2 使用django-redis

# 安装  pip install django-redis
# redis的配置,django缓存的配置,以后django的缓存也用redis了
# 配置文件
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100},
            "DECODE_RESPONSES": True,
            # "PASSWORD": "",
        }
    }
   
}
# 使用
from django_redis import get_redis_connection
conn=get_redis_connection('default')  # 指定使用哪个配置
conn.set('age',19)

1.3 django 中使用,建议使用这种方法(常用)

# 也会存到redis中,最大的好处,cache.set的value值,可以是python的任意类型对象
from django.core.cache import cache
cache.set('hobby',['篮球','足球']) 
res=cache.get('hobby')
# cache帮咱们做了封装,可以缓存任意的python对象
# django缓存的内部,拿到对象转成了二进制(pickle),存到了redis中

2 celery介绍和架构

# celery:(芹菜),分布式   异步任务  框架 ,对win支持不好
Celery is a project with minimal funding, so we don’t support Microsoft Windows. Please don’t open any issues related to that platform.

#Celery的架构由三部分组成, 
消息中间件(message broker):需要使用第三方,reids,rabbitmq等 #提交任务的地方
任务执行单元(worker):celery提供的 #执行任务的地方
任务执行结果存储(task result store):使用第三方 redis等 #任务完成的结果的地方 

pip install celery


# 使用场景
异步执行:解决耗时任务,将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等
延迟执行:解决延迟任务
定时执行:解决周期(周期)任务,比如每天数据统计

#cerely主要是提高并发量

3 celery快速使用

####### 第一步:写一个py文件,实例化得到app,编写任务
from celery import Celery
broker='redis://127.0.0.1:6379/1' #消息中间件
backend='redis://127.0.0.1:6379/2' #结果存储
app = Celery(__name__,backend=backend,broker=broker) #__name__等于app对象的名字

#写任务 也可以说叫函数,使用装饰器装饰一下

@app.task
def add(a,b):
    import time
    time.sleep(2)
    return a+b
######## 第二步:在其他系统中,提交任务,(导入任务)
from main import add

#同步调用,不叫提交任务
# res=add(3,4)
# print(res)

#异步执行,先提交任务,并不执行
res=add.apply_async(args=[3,4])
#返回结果是任务的id号61bdfa12-95b1-46e4-b020-40db8113bc47
print(res)



#### 第三步:启动worker执行任务
# 使用命令启动worker
# win机器,需要安装 eventlet
# pip install eventlet
#      启动命令        -A启动那个文件 -l日志界别 -P win下才加
# 3.x 及以前:celery worker -A main -l info -P eventlet
# 4.x及以后:celery -A main worker -l info -P eventlet

# linux执行下面:区别在于linux不用加-P参数
celery -A main worker -l info


### 第四步:worker就会从任务中取出任务执行

### 第五步:查看任务执行结果
#查询结果 根据id查询 还有app名字

from main import app
from celery.result import AsyncResult
id = '61bdfa12-95b1-46e4-b020-40db8113bc47'
if __name__ == '__main__':
    asy = AsyncResult(id=id, app=app)
    if asy.successful(): # 顺利执行完了,可以取结果了
        res = asy.get()  # 获取任务执行的结果
        print(res)
    elif asy.failed():
        print('任务失败')
    elif asy.status == 'PENDING':
        print('任务等待中被执行')
    elif asy.status == 'RETRY':
        print('任务异常后正在重试')
    elif asy.status == 'STARTED':
        print('任务已经开始被执行')

4 包管理形式

#上面的方式正式项目不那么用 都采用下面的方式 包管理形式,写好之后这个包可以直接拿到项目使用
#### 第一步:建立如下格式
celery_task  # 包名
    __init__.py
    celery.py  # 必须叫这个名字 存放的是app等配置文件的名字
    course_task.py # 一堆任务
    home_task.py # 一堆任务
    user_task.py # 一堆任务
    任务提交-正常不写在这.py  #正常写在谁用写在谁里面
    结果查看--正常也不写在这.py #正常写在谁用写在谁里面

### 第二步,在celery.py中写入
from celery import Celery
broker='redis://127.0.0.1:6379/1'   # 消息中间件
backend='redis://127.0.0.1:6379/2'  # 结果存储
# include 表示哪些py文件的任务被app管理
app = Celery(__name__,backend=backend,broker=broker,include=['celery_task.course_task','celery_task.home_task','celery_task.user_task'])

### 第三步:写好多任务
from .celery import app   # 使用相对路径导入
import time
@app.task
def send_sms(phone,code):
    print('短信发送成功','手机号为:%s,code为:%s'%(phone,code))
    time.sleep(1)
    return '手机号为:%s,code为:%s'%(phone,code)


### 第四步:启动worker,在包这一层路径 包在的文件夹路径比如scripts里面有一个包a  那么就需要在scprits文件夹下,而不是文件夹a下
#celery -A 包名 worker -l info -P eventlet
celery -A celery_task worker -l info -P eventlet


####第五步:提交任务(什么时候提交都可以)
from celery_task.user_task import send_sms
res=send_sms.apply_async(args=['3354325334',5555])
print(res)  # eb89760d-73fe-41c9-a7a5-6ae91f811aa1


### 第六步:结果查看
from celery_task.celery import app

from celery.result import AsyncResult

id = 'eb89760d-73fe-41c9-a7a5-6ae91f811aa1'
if __name__ == '__main__':
    asy = AsyncResult(id=id, app=app)
    if asy.successful(): # 顺利执行完了,可以取结果了
        res = asy.get()  # 任务执行的结果
        print(res)
    elif asy.failed():
        print('任务失败')
    elif asy.status == 'PENDING':
        print('任务等待中被执行')
    elif asy.status == 'RETRY':
        print('任务异常后正在重试')
    elif asy.status == 'STARTED':
        print('任务已经开始被执行')

5 执行异步任务和延迟任务

# 异步任务
res=任务.delay(参数1,参数2)
print(res)

# 延迟任务
from datetime import datetime, timedelta
#当前时间+一分钟之后
eta=datetime.utcnow() + timedelta(minutes=1)
# eta是一个时间对象,不能传数字
res=send_sms.apply_async(args=['18953675221',8888],eta=eta)
print(res)

6 执行定时任务

##############第一步: 在celery.py中加入
# 修改app的配置文件
# 时区
app.conf.timezone = 'Asia/Shanghai'
# 是否使用UTC
app.conf.enable_utc = False

# 任务的定时配置
from datetime import timedelta
from celery.schedules import crontab
app.conf.beat_schedule = {
    'send_sms':{
        'task': 'celery_task.user_task.send_sms',
        'schedule': timedelta(seconds=3),  # 每隔3s
        # 'schedule': crontab(hour=8, day_of_week=1),  # 每周一早八点
        'args': ('12345667', 8888),
    }
}

####第二步:启动worker和beat

# 启动两个任务(worker 和 beat)
# 启动beat自动提交 

celery -A celery_task beat -l info   #启动beat
celery -A celery_task worker -l info -P eventlet #启动worker  执行任务

7 路飞项目中使用

# 轮播图
# 定时更新轮播图缓存 不用每次都去数据库查询

# 在脚本中加入可执行djagno的命令
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "luffy.settings.dev")

# 加入缓存,会有问题,缓存不一致----》双写一致性
	-先删缓存,再写mysql
	-先写mysql,删除缓存
    -先写mysql,更新缓存
    -定时更新
  

#celery配置
app.conf.beat_schedule = {
    'update_banner': {
        'task': 'celery_task.home_task.banner_update',
        'schedule': timedelta(seconds=3),  # 每隔3s
        # 'schedule': crontab(hour=8, day_of_week=1),  # 每周一早八点
        'args': (),
    }
}
    
# 轮播图加缓存
    def list(self, request, *args, **kwargs):
        # 先去缓存中查数据,如果有,之间返回
        res = cache.get('banner_list')
        if res:
            #走了缓存
            print('走了缓存')
            return Response(data=res)
        else:
            print('没走缓存')
            # 如果没有,去数据库查,放入缓存
            response = super().list(request, *args, **kwargs)
            cache.set('banner_list', response.data)
            return response
        
        
# 任务:
def banner_update():
from .celery import app
from django.core.cache import cache
from django.conf import settings
from home.models import Banner
from home.Serializer import BannerSerializer

@app.task
def banner_update():
    # 往django缓存中写入轮播图数据
    queryset = Banner.objects.all().filter(is_delete=False, is_show=True)[:settings.BANNER_COUNT]
    ser = BannerSerializer(instance=queryset, many=True)
    for item in ser.data:
        item['image'] = 'http://127.0.0.1:8000' + item['image']
    cache.set('banner_list', ser.data)
    



# 启动beat,和worker
celery -A celery_task beat -l info  #beat 执行任务

celery -A celery_task worker -l info -P eventlet  #存储任务

posted @ 2022-02-28 20:47  迪迦张  阅读(114)  评论(0编辑  收藏  举报