【发布时间】:2021-11-20 06:08:47
【问题描述】:
我们在 EC2 上运行的 docker 容器内有一个机器学习模型。
我们使用 Cortex.dev 来自动扩展 GPU。
不确定地,请求将在 FastAPI 中间件中的 call_next 函数期间挂起。不幸的是,它无法重现。
Middleware pre-request 打印行被记录,但路径操作函数中的第一个打印语句从未被记录。
我们尝试过的事情:
- 使用 1 名工人运行 Uvicorn
- 在没有异步的情况下运行
run函数 - 以
bytes作为image的参数类型而不是UploadFile运行
这些更改都不能解决挂起的问题,但这是性能最高的配置。
-
这是否意味着问题出在 FastAPI 而不是 Uvicorn?
-
如果是,什么会导致 FastAPI 挂起?如果不是,问题出在哪里?如何解决?
Dockerfile
FROM nvidia/cuda:11.4.0-runtime-ubuntu18.04
WORKDIR /usr/src/app
RUN apt-get -y update && \
apt-get install -y --fix-missing \
build-essential \
cmake \
python3 \
python3-pip \
ffmpeg \
libsm6 \
libxext6 \
&& apt-get clean && rm -rf /tmp/* /var/tmp/*
ADD ./requirements.txt ./
# install our dependencies
RUN python3 -m pip install --upgrade pip && python3 -m pip install -r requirements.txt && apt-get clean && rm -rf /tmp/* /var/tmp/*
ADD ./ ./
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8
EXPOSE 8080
CMD uvicorn api:app --host 0.0.0.0 --port 8080 --workers 2
api.py
from my_predictor import PythonPredictor
from typing import Optional
from datetime import datetime
import time
from starlette.responses import Response
from fastapi import FastAPI, File, UploadFile, Form, Response, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
cortex_id = request.headers.get('x-request-id')
start_time = time.time()
print("Cortex ID: " + cortex_id + ". > Middleware pre-request. Time stamp: " + str(start_time), flush=True)
response = await call_next(request)
process_time = time.time() - start_time
print("Cortex ID: " + cortex_id + ". > Middleware post-response. Duration: " + str(process_time), flush=True)
return response
@app.post("/")
async def run(request: Request, image: UploadFile = File(...), renderFactor:Optional[int] = Form(12), requestId:Optional[str] = Form('-1'),include_header:Optional[str] = Form('bin')):
try:
cortexId = request.headers.get('x-request-id')
print("Cortex ID: " + cortexId + ". Request ID: " + requestId + " >>> Request received. Time stamp: " + str(datetime.now()))
start = time.time()
image = await image.read()
payload = {}
payload['image'] = image
payload['renderFactor'] = renderFactor
payload['requestId'] = requestId
payload['include_header'] = include_header
response = pred.predict(payload)
end = time.time()
totalTime = round(end - start, 2)
print("Cortex ID: " + cortexId + ". Request ID: " + requestId + " > Request processed. Duration: " + str(totalTime) + " seconds. Time stamp: " + str(datetime.now()))
if totalTime > 5:
print("Long request detected. Duration: " + str(totalTime))
return response
except Exception as error:
end = time.time()
print(str(error))
print("Cortex ID: " + cortexId + ". Request ID: " + requestId + " > Error. Duration: " + str(round(end - start, 2)) + " seconds . Time stamp: " + str(datetime.now()))
raise HTTPException(status_code = 500, detail = str(error))
config = {}
pred = PythonPredictor(config)
【问题讨论】:
-
docker exec -it ${image_id} bash进入正在运行的容器并使用 gdb 进行调试 - wiki.python.org/moin/DebuggingWithGdb -
@NikitaAlmakov 感谢您的帮助。我们能够生成此跟踪,但我坚持隔离导致容器挂起的确切原因:gist.github.com/panabee/1710b94f2a6d1291051b55f26bab54fc。还有什么建议吗?
-
尝试检查每个线程:
info threads,例如thread 2然后是py-up、py-down和py-list命令来查看堆栈的每个级别 - devguide.python.org/gdb -
您可以尝试使用 http 202 作为解决方法吗? github.com/tiangolo/fastapi/issues/3
-
另外,请检查此票证以了解非阻塞异步和配置 uvicorn 以进行长时间请求
标签: python python-requests fastapi uvicorn