Django FileResponse处理大文件崩溃,树莓派宕机求助
解决思路与建议
1. 重构备份流程,避免内存中处理大文件
- 数据库导出直接写入磁盘:用
mysqldump命令导出MariaDB,直接输出到临时文件,禁止在Python内存中缓存输出内容。示例调用:
用Pythonmysqldump -u 用户名 -p密码 数据库名 > /tmp/db_backup.sqlsubprocess执行时,指定stdout为磁盘文件对象,不要捕获输出到内存变量。 - ZIP打包优先用磁盘文件:用系统
zip命令直接打包磁盘上的文件到临时ZIP,或用Pythonzipfile.ZipFile以w模式写入磁盘,绝对禁止用BytesIO作为ZIP输出目标(会把整个6GB文件加载到内存)。
2. 优化Django文件响应配置
- 显式设置
FileResponse分块大小:初始化时指定chunk_size=65536(64KB),强制按块读取文件,避免一次性加载:from django.http import FileResponse def backup_download(request): backup_file = open('/tmp/backup.zip', 'rb') response = FileResponse(backup_file, chunk_size=65536) response['Content-Disposition'] = 'attachment; filename="backup.zip"' return response - 禁用缓冲类中间件:暂时关闭
GZipMiddleware,大文件压缩会占用大量内存,若需压缩可让Nginx处理静态文件压缩逻辑。 - 给Daphne设置内存上限:在systemd配置文件中添加
MemoryLimit=4G(根据树莓派实际内存调整),避免进程耗尽内存拖垮系统。
3. 调整Nginx反向代理配置
- 延长超时并关闭缓冲:在Nginx的location配置中添加以下参数,适配大文件下载的长时长需求,同时避免Nginx自身缓存响应占用内存:
location / { proxy_pass http://localhost:8000; proxy_connect_timeout 600s; proxy_send_timeout 600s; proxy_read_timeout 600s; proxy_buffering off; proxy_http_version 1.1; proxy_set_header Connection ""; }
4. 改用异步视图处理下载
Daphne是异步服务器,同步视图可能阻塞事件循环并引发内存异常,改用异步视图配合aiofiles分块读取文件:
import aiofiles import asyncio from django.http import StreamingHttpResponse from django.views import View from django.utils.decorators import classonlymethod class BackupDownloadView(View): @classonlymethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) view._is_coroutine = asyncio.coroutines._is_coroutine return view async def get(self, request): async def file_iterator(): async with aiofiles.open('/tmp/backup.zip', 'rb') as f: while chunk := await f.read(65536): yield chunk response = StreamingHttpResponse(file_iterator()) response['Content-Disposition'] = 'attachment; filename="backup.zip"' return response
5. 系统层面优化
- 增加交换分区:树莓派内存有限,创建2GB交换分区缓解内存压力:
sudo fallocate -l 2G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile - 降低备份任务优先级:用
nice命令降低mysqldump和zip的优先级,避免抢占Daphne、MariaDB的资源:nice -n 19 mysqldump ... > /tmp/db_backup.sql nice -n 19 zip -r /tmp/backup.zip /tmp/db_backup.sql /path/to/other/data - 优化MariaDB导出参数:添加
--quick和--single-transaction减少导出时的内存占用:mysqldump --quick --single-transaction -u 用户名 -p密码 数据库名 > /tmp/db_backup.sql
6. 排查内存暴增根源
- 用
psutil模块在备份流程关键节点打印内存使用,定位是数据库导出、ZIP打包还是文件响应阶段内存飙升:import psutil import os def get_memory_usage(): process = psutil.Process(os.getpid()) return process.memory_info().rss / 1024 / 1024 # 单位MB # 在备份、打包、响应等步骤中调用print(get_memory_usage()) - 确认ZIP文件是直接写入磁盘,而非用
BytesIO在内存中生成——这是大文件场景的常见内存泄漏坑。
内容的提问来源于stack exchange,提问作者LudgerH
相关产品推荐
相关产品推荐

