Gunicorn+FastAPI+Detoxify部署在AWS Fargate的性能问题求助
优化Detoxify模型在AWS Fargate CPU环境下的API性能
当前基于Detoxify的字符串毒性检测API部署在4核vCPU/8GB内存的AWS Fargate CPU实例上,采用FastAPI+Gunicorn架构(3个worker,预加载模型),但存在明显性能瓶颈:
/toxicity端点最高吞吐量仅20-25req/sec,100并发客户端下响应时长达8秒- 10并发客户端时响应时长700ms,但吞吐量仍维持在20req/sec左右,未随并发提升
- 对比
/healthcheck端点3.8k req/sec的吞吐量,瓶颈集中在模型推理环节
1. 调整Gunicorn Worker配置
CPU密集型任务(模型推理)的worker数量需匹配CPU核心数,避免过度上下文切换:
- 将worker数从3调整为4(4核实例最优值,也可测试2*核数=8的效果)
- 修改启动命令,增大请求等待队列、延长连接保持时间:
CMD gunicorn app.server:app --workers 4 --preload --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:8080 --keep-alive 30 --backlog 2048
- 说明:
--preload确保模型在fork worker前加载,实现内存共享;--backlog避免高并发下请求被直接拒绝;延长--keep-alive减少TCP握手开销
2. 实现批量请求处理
Detoxify原生支持批量输入,单条请求处理会浪费CPU算力,改为批量处理可大幅提升吞吐量:
修改FastAPI接口,支持接受字符串列表:
from fastapi import FastAPI, HTTPException from pydantic import BaseModel from detoxify import Detoxify from typing import List app = FastAPI() model = Detoxify("unbiased-small", device="cpu") @app.get("/healthcheck") def healthcheck(): return {"status": "OK"} @app.get("/healthcheck/loadbalancer") def healthcheck_lb(): return {"status": "OK"} # 新增批量POST接口,提升吞吐量 @app.post("/toxicity/batch") def predict_batch(texts: List[str]): try: results = model.predict(texts) # 按输入顺序返回结果,方便客户端对应 return [ {key: results[key][i] for key in results} for i in range(len(texts)) ] except Exception as e: raise HTTPException(status_code=400, detail=str(e)) # 保留单条请求接口,兼容原有调用 @app.get("/toxicity") def predict(q: str): try: return model.predict([q]) except Exception as e: raise HTTPException(status_code=400, detail=str(e))
- 客户端可批量发送10-50条请求,吞吐量可提升数倍(具体批量大小需测试最优值)
3. 模型推理优化
3.1 限制CPU线程竞争
设置环境变量,让每个worker独占1个CPU线程,避免多worker抢占资源:
在Dockerfile中添加:
ENV OMP_NUM_THREADS=1 ENV MKL_NUM_THREADS=1
- 4个worker刚好占满4核,最大化CPU利用率
3.2 切换轻量模型或量化模型
- 尝试使用Detoxify的
original-small模型,比unbiased-small更小,推理速度更快(精度略有损失,需评估业务可接受度) - 将模型转换为ONNX格式,使用ONNX Runtime推理,CPU性能可提升30%-50%:
# 转换模型为ONNX(仅需执行一次,保存到文件) import torch from detoxify import Detoxify model = Detoxify("unbiased-small", device="cpu") torch_model = model.model example_input = torch.tensor([[1, 2, 3]]) # 匹配模型输入维度 torch.onnx.export( torch_model, example_input, "detoxify_model.onnx", opset_version=11, input_names=["input_ids"], output_names=["logits"] ) # 加载ONNX模型推理 import onnxruntime as ort import numpy as np from detoxify import build_tokenizer tokenizer = build_tokenizer("unbiased-small") ort_session = ort.InferenceSession("detoxify_model.onnx") def predict_onnx(text): inputs = tokenizer(text, return_tensors="np", padding=True, truncation=True) input_ids = inputs["input_ids"] outputs = ort_session.run(None, {"input_ids": input_ids}) logits = outputs[0] probabilities = np.exp(logits) / np.sum(np.exp(logits), axis=-1, keepdims=True) return { "toxicity": probabilities[:, 0].tolist(), "severe_toxicity": probabilities[:, 1].tolist(), "obscene": probabilities[:, 2].tolist(), "threat": probabilities[:, 3].tolist(), "insult": probabilities[:, 4].tolist(), "identity_attack": probabilities[:, 5].tolist() }
4. Fargate资源与负载均衡优化
- 监控Fargate实例CPU使用率:若CPU未跑满(<70%),检查worker数量或线程设置;若CPU持续跑满,可升级到8核16GB实例(成本增加,但吞吐量可翻倍)
- 调整负载均衡器连接超时时间至10秒以上,避免负载均衡器提前断开长响应请求
内容的提问来源于stack exchange,提问作者Garbit
相关产品推荐
相关产品推荐

