大文件上传超时问题咨询(Django+Minio架构)
解决Django+Minio大文件上传超时问题
针对你当前的架构(用户先传Django再内网转存Minio),超时问题主要来自两个环节:用户上传到Django的请求超时,以及Django同步转存Minio时的后台耗时过长。以下是具体解决方案:
1. 调整基础超时配置
Django 端设置
修改settings.py,放宽文件上传的内存限制和临时存储配置:
# 允许上传的最大文件大小(示例:10GB) FILE_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 * 1024 DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 * 1024 # 指定临时文件存储目录(确保有足够磁盘空间) FILE_UPLOAD_TEMP_DIR = '/path/to/large-temp-dir'
Web 服务器配置
如果用Nginx作为反向代理,修改站点配置文件:
# 允许客户端上传的最大文件大小 client_max_body_size 10G; # 延长代理读取/连接超时时间 proxy_read_timeout 300s; proxy_connect_timeout 300s; proxy_send_timeout 300s;
如果用Gunicorn作为WSGI服务器,启动时增加超时参数:
gunicorn your_project.wsgi:application --timeout 300 --keep-alive 60
2. 异步转存Minio,避免阻塞用户请求
同步转存Minio会让用户请求一直等待,直接触发超时。改用异步任务处理转存:
用Celery实现异步转存
- 安装Celery并配置消息队列(如Redis或RabbitMQ)
- 编写异步任务(
tasks.py):
from celery import shared_task from minio import Minio from django.conf import settings import os @shared_task def upload_to_minio(local_file_path, bucket_name, object_name): # 初始化Minio内网客户端 minio_client = Minio( settings.MINIO_INTERNAL_ENDPOINT, access_key=settings.MINIO_ACCESS_KEY, secret_key=settings.MINIO_SECRET_KEY, secure=False # 内网传输可关闭HTTPS ) # 检查桶是否存在,不存在则创建 if not minio_client.bucket_exists(bucket_name): minio_client.make_bucket(bucket_name) # 上传文件到Minio minio_client.fput_object(bucket_name, object_name, local_file_path) # 清理本地临时文件 os.remove(local_file_path)
- 在视图中调用异步任务,立即返回响应:
from django.http import JsonResponse from .tasks import upload_to_minio from django.conf import settings import os def upload_file(request): if request.method == 'POST' and request.FILES.get('file'): uploaded_file = request.FILES['file'] # 保存到临时目录 temp_file_path = os.path.join(settings.FILE_UPLOAD_TEMP_DIR, uploaded_file.name) with open(temp_file_path, 'wb+') as destination: for chunk in uploaded_file.chunks(): destination.write(chunk) # 异步执行转存任务,不阻塞用户请求 upload_to_minio.delay(temp_file_path, 'your-bucket-name', uploaded_file.name) return JsonResponse({'status': 'success', 'message': '文件已提交,后台正在处理'}) return JsonResponse({'status': 'error'}, status=400)
3. 最优方案:让用户直接上传到Minio(绕过Django中转)
彻底避免Django作为中转的性能瓶颈,让前端直接通过Minio预签名URL上传:
Django生成预签名上传URL
from minio import Minio from django.conf import settings from django.http import JsonResponse def get_presigned_upload_url(request): if request.method == 'GET': file_name = request.GET.get('file_name') bucket_name = 'your-bucket-name' minio_client = Minio( settings.MINIO_EXTERNAL_ENDPOINT, access_key=settings.MINIO_ACCESS_KEY, secret_key=settings.MINIO_SECRET_KEY, secure=True # 外网传输建议开启HTTPS ) # 生成有效期1小时的预签名上传URL presigned_url = minio_client.presigned_put_object(bucket_name, file_name, expires=3600) return JsonResponse({'presigned_url': presigned_url, 'file_name': file_name}) return JsonResponse({'status': 'error'}, status=400)
前端直接上传到Minio
前端拿到预签名URL后,直接上传文件,无需经过Django:
async function uploadFileToMinio(file) { // 先请求Django获取预签名URL const urlResp = await fetch(`/get-presigned-url/?file_name=${file.name}`); const urlData = await urlResp.json(); // 直接上传到Minio await fetch(urlData.presigned_url, { method: 'PUT', body: file, headers: {'Content-Type': file.type} }); // 上传完成后通知Django记录文件信息 await fetch('/record-file/', { method: 'POST', body: JSON.stringify({file_name: urlData.file_name}), headers: {'Content-Type': 'application/json'} }); }
4. 分块上传(针对超大文件)
如果文件超过10GB,建议用分块上传,每块大小设为50MB-100MB,避免单块上传超时:
- Minio原生支持分块上传,结合预签名URL实现前端分块上传
- Django端可处理分块的合并逻辑(或直接由Minio自动合并)
内容的提问来源于stack exchange,提问作者lornejad
相关产品推荐
相关产品推荐

