我用 Flask 和 Gunicorn 构建了一个简单的 docker Web 应用程序。一切正常,但偶尔在发出请求时,响应会挂起。在工作人员超时之前,我在日志记录中看不到任何内容。因此,看起来工作人员正忙于某事,超时,然后新工作人员收到请求并立即响应。
我只用了 1 名工人就完成了安装。我知道我可以添加另一个工人。但除了我手动戳之外,没有其他请求。没有其他事情发生。所以我很好奇这个工作人员或主gunicorn工作人员还会在容器中做什么(心跳,错误处理那么昂贵)?
我的 Dockerfile:
FROM python:3.6-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt --no-cache-dir
EXPOSE 5000
CMD ["gunicorn", "-w", "1", "-t", "30", "--worker-tmp-dir", "/dev/shm", "-b", "0.0.0.0:5000", "app:app"]
我的小应用程序:
import logging
import model
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.errorhandler(Exception)
def handle_error(e):
code = 500
app.log_exception(e)
return jsonify(message=str(e)), code
@app.route("/predict", methods=["POST", "GET"])
def predict():
result = model.predict(None)
return jsonify(result)
model = model.mcascorer()
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
else:
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
我的超级小“模型”我称之为预测:
class mcascorer:
def predict_proba(self, features):
return 'hello'
def predict(self, features):
return 'hello'
通常会立即响应,但在超时期间日志如下所示:
[2020-05-21 18:09:28 +0000] [9] [DEBUG] Closing connection.
[2020-05-21 18:09:58 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:9)
[2020-05-21 18:09:58 +0000] [9] [INFO] Worker exiting (pid: 9)
[2020-05-21 18:09:58 +0000] [11] [INFO] Booting worker with pid: 11
[2020-05-21 18:09:58 +0000] [11] [DEBUG] GET /predict
工作人员似乎被其他事情阻碍了 - 但我不知道那会是什么。同时传入的心跳查询不应花费那么长时间,但它会挂起很多秒 - 我实际上为工作人员设置的整个超时持续时间。唯一发生的另一件事是错误日志记录,但不确定为什么会阻塞或花费这么长时间。即使它正在写入磁盘,这也看起来很奇怪。
我能找到的最接近的问题在这里:Docker:通过 Gunicorn 运行 Flask 应用程序 - Worker 超时?表现不佳? 链接到这篇文章: https://pythonspeed.com/articles/gunicorn-in-docker/
我按照他们的指南更新了 tmp 内存位置“--worker-tmp-dir”、“/dev/shm”的 Dockerfile
我没有添加更多工人。我知道我可以,但我真的很想知道发生了什么,而不是盲目地投入资源。任何想法都非常感激。
这里讨论:https://github.com/benoitc/gunicorn/issues/1923 他们提出了 2 个解决方案:
--threads 2
或更高级别至gunicorn
--preload
旗帜
对我来说,第一个解决方案有效。我还没试过第二个。我猜问题是你有一个工作人员正在做一项“繁重的工作”,其时间超过了默认的工作人员超时时间。
所以你需要:
CMD gunicorn --timeout 1000 ...
我还建议使用 FastAPI(和
async
路由器)而不是同步烧瓶