上传文件、异步、初始化脚本
面试题:
项目中的静态文件处理(JS/CSS/image) 自己在机房内优化的方法:1. Nginx/lighttpd(lighty-douban):Nginx 处理静态资源速度非常快,并且自身还带有缓存。2. 80: Nginx -> {server config} -> django:8080 -> Static : folders -> 云存储你了解CDN吗?能讲讲原理么?扩展:如何更换CDN上的图片?改名大法1. 请求加参数:1. abc.jpg2. abc.jpg?20191011111042asdflj23. abc.jpg?201910111110432. 改名1. abc_201910111042.jpg2. abc_md5.jpg
七牛云接入
- 注册七牛云账号
- 创建存储空间:Bucket -> 有独立的域名,可以访问
- 获取相关配置
- AccessKey:从个人中心-密钥管理里获得
- SecretKey:从个人中心-密钥管理里获得
- Bucket_name:我们自己新建的存储空间的名字
- Bucket_URL:建好的新存储空间的访问url
- 安装 qiniu SDK:
pip install qiniu
- 根据接口文档进行接口封装
- 按照需要将上传、下载接口封装成异步任务
- 程序处理流程
- 服务端上传方式
- 用户图片先上传到我们的服务器上
- 然后,我们的程序再调用七牛云的api,将图片上传到七牛云
- 上传成功后,拼接 avatar 的图片 url 地址:
- 七牛云的Bucket_URL/filename,将 avatar 的图片 url 存入数据库
- 客户端直传
- 客户端图片直接上传到云服务
- 客户端将图片地址告诉服务端,服务端更新数据库
- 其实存在一个安全隐患
- 客户端先从服务端获取token,再上传
- 服务端上传方式
代码示例 使用了celery
#上传图片
def user_avatar(request):#1.存下来# 定义上传后保存的文件名file_name =f'avatar-{request.user.id}.jpg'# 上传后保存的路径file_path = f'{settings.BASE_DIR}/static/{file_name}'#接收上传文件内容f = request.FILES['avatar']with open(file_path,'wb+') as destination:for chunk in f.chunks():destination.write(chunk)print('save local ok.')user_id = request.user.id#delay很重要!!!upload_qiniu.delay(file_name, file_path, user_id)return render_json('已经放入celery-redis队列中')#这一步用异步celery
@celery_app.task
def upload_qiniu(file_name, file_path, user_id):# 2.调用七牛云sdk上传# 需要填写你的 Access Key 和 Secret Key 需要修改 access_key = 'KXfx2ZiBP311HkZZ8l8JHCmqlqPTJCK2sraihexx'secret_key = 'pe5svTTUAJQoUPhppsf0Gg9wbEJiYahnRMAy1rxx'# 要上传的空间bucket_name = 'liu'# 要上传的域名bucket_domain = ' liu.s3-cn-south-1.qiniucs.com'# 构建鉴权对象q = Auth(access_key, secret_key, )token = q.upload_token(bucket_name, file_name, 3600)ret, info = put_file(token, file_name, file_path)print(info)#断言assert ret['key'] == file_nameassert ret['hash'] == etag(file_path)print('save qiniu ok.')avatar_url = f'{bucket_domain}/{file_name}'# 3.更新用户的avataruser = User.objects.get(id=user_id)# user = request.user # request 无法传 所以改为user_iduser.avatar = avatar_urluser.save()return True
异步任务
Celery 及异步任务的处理
-
通用的异步框架的原理
-
核心队列:消息队列
-
客户端:异步端
-
生产者:消费者
-
发布者:订阅者
-
发送者:接收者
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YFOxnBJs-1577967577874)(/Users/zebin/Pictures/markdown_assets/image-20200102152154116.png)]
-
任务模块 Task:包含异步任务和定时任务. 其中, 异步任务通常在业务逻辑中被触发并发往任务队列, 而定时任务由 Celery Beat 进程周期性地将任务发往任务队列.
-
消息中间件 Broker:代理Broker, 即为任务调度队列, 接收任务生产者发来的消息(即任务)更重要的智能是把海量的的消息缓冲住, 将任务存入队列。Celery 本身不提供队列服务, 官方推荐使用 RabbitMQ 和 Redis 等,或者干脆用云服务的消息队列服务:SQS
-
任务执行单元 Worker:Worker 是执行任务的处理单元, 它实时监控消息队列, 获取队列中调度的任务, 并执行它.
-
任务结果存储 Backend:Backend 用于存储任务的执行结果, 以供查询. 同消息中间件一样, 存储也可使用 RabbitMQ, Redis 和 MongoDB 等.
-
-
消息队列:
- MQ:Message Queue,(与服务器、存储、缓存、数据库同等重要,是现代互联网后台架构的基础组件)
- 作用:
- 异步:把没必要同步执行的程序,用消息队列暂存,然后用其他程序去异步执行,做到跨机器分散任务
- 解耦:有依赖关系的应用之间,用消息队列解除耦合
- A 和 B 两个业务有强耦合
- A
B
- 削峰:把互联网的高峰请求,先缓冲下来,然后再慢慢的逐个处理
- 秒杀、团购的场景,用这种方式降低峰值请求
- 限流:
- 1000,每进来一个人 -1,每离开一个人 +1,
- 减到 0 ,就告诉后来者:人满了。
- 常见的消息队列:
- Redis,最简单
- Kafka,最适合做日志处理,单机几十万并发(每秒钟的请求)
- RabbitMQ,符合 MQ 标准的消息队列(每秒钟几万)
- RocketMQ,符合 MQ 标准的消息队列(每秒钟十几万)
-
安装 注意win10不支持celery4.3!!!!!!!!!!
所以需要额外安装pip install celery[redis]
-
创建实例
import os from celery import Celeryfrom social import settings from worker import configos.environ.setdefault("DJANGO_SETTINGS_MODULE", "social.settings")celery_app = Celery('social') celery_app.config_from_object(config) celery_app.autodiscover_tasks()
-
常规配置
broker_url = 'redis://127.0.0.1:6379/0' broker_pool_limit = 1000 # Borker 连接池, 默认是10timezone = 'Asia/Shanghai' accept_content = ['pickle', 'json']task_serializer = 'pickle' result_expires = 3600 # 任务过期时间result_backend = 'redis://127.0.0.1:6379/1' result_serializer = 'pickle' result_cache_max = 10000 # 任务结果最大缓存数量worker_redirect_stdouts_level = 'INFO'
-
启动 Worker
Linux / mac下:
celery worker -A worker --loglevel=info
win:
celery worker -A worker --loglevel=info -P eventlet