我在 Linux ( 4.9.13 ) 上使用带有 Python 3.7 的 Flask ( 1.0.2 ) 和由 NGINX ( 1.15.7 ) 代理的 Gunicorn ( 19.9.0 )。
我可以使用以下代码将一个大 ( 1.2GB ) 文件成功上传到我的 Flask 服务器。但是,整个文件在使用如下所示的 file.save() 函数写入磁盘之前先缓存在 RAM 中。我试过谷歌搜索并发现各种帖子据称将文件流式传输到磁盘而不是在 RAM 中缓冲,但我一直无法让他们的方法起作用。
如何让文件直接流式传输到磁盘,而不是先在 RAM 中缓冲,然后再到磁盘?
这是我启动 gunicorn 的方式:
gunicorn --workers=4 --threads=8 --bind localhost:8000 StartFlaskServer:app
这是我的 Flask 端点代码:
@app.route("/firmware_update", methods=["GET", "POST"])
def upload_video():
if request.method == "POST":
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return make_response(jsonify({"message": "No File Part Specified!"}), 500)
file = request.files['file']
# if user does not select file, browser also
# submit an empty part without filename
if file.filename == '':
flash('No selected file')
return make_response(jsonify({"message": "No Selected File!"}), 500)
if not allowed_file(file.filename):
suffix = file.filename.rsplit('.', 1)[1].lower()
return make_response(jsonify({"message": "Filetypes of %s not accepted ( Must be of type: %s )!"%(suffix,ALLOWED_EXTENSIONS)}), 500)
fileFullPath = os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(request.files['file'].filename))
# Why does this not work? Cannot convert file to stream type with no buffering in NGINX?
# with open(fileFullPath, "wb") as f:
# chunk_size = 4096
# while True:
# chunk = request.stream.read(chunk_size)
# print("Flask Writing Chunk: %s"%(len(chunk)))
# if len(chunk) == 0:
# break
# print("Wrote this much: %s"%(f.write(chunk)))
file.save(fileFullPath)
return make_response(jsonify({"message": "File uploaded"}), 200)
return render_template("upload_firmware_bundle.html")
这是我的 NGINX 端点配置:
# Proxy upload
location /firmware_update {
# Proxy config
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Do not buffer body
client_max_body_size 0;
proxy_http_version 1.1;
proxy_buffering off;
proxy_request_buffering off;
}
最佳答案
谷歌搜索后我找到了large file uploads eating up memory在 werkzeug 问题中。 Ivarref 发布了 version这不会消耗大量内存。
我还没有发现文件上传处理的源代码。但是,我猜想 werkzeug(或 flask )在将文件交给用户之前将所有内容加载到内存中。通过直接处理 request.environ,我们绕过了该逻辑并避免消耗过多内存。
编辑:我检查了 werkzeug 的源代码,发现如果 Request.files被访问,它会调用Request._load_form_data ,然后将创建 Request.form_data_parser_class 的实例. Request.form_data_parser_class
的默认值为 werkzeug.FormParser , 使用 default_stream_factory作为流工厂。似乎在某些情况下,default_stream_factory
会回退到BytesIO
作为临时文件,这会导致将文件内容存储在内存中并占用大量内存。
关于python - 通过 Gunicorn 上传 Flask 和 NGINX 流式文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57610929/