本文會使用如下兩個項目:meinheld-gunicorn-flask 與 uvicorn-gunicorn-fastapi
前文有測過 Flask vs FastApi 性能對比測試,可能不夠有說服力,這次使用了號稱最快的wsgi或asgi服務器+gunicorn來運行flask或fastapi。
上面meinheld-gunicorn-flask和uvicorn-gunicorn-fastapi項目都是由fastapi的作者發起,致力于使用flask或fastapi開發高性能后端應用,然后用docker的方式快速部署。文末會給出測試結論。
名詞解釋
meinheld:高性能wsgi服務器
uvicorn:高性能asgi服務器
gunicorn:用來管理meinheld或uvicorn的運行,比如用多進程/多線程的方式運行meinheld或uvicorn,以便最大化性能來運行flask或fastapi程序。
測試環境
Ubuntu 22.04系統,CPU 16核,內存32G。
一、創建 meinheld-gunicorn-flask-test 目錄,目錄結構為
meinheld-gunicorn-flask-test
├── Dockerfile
├── app
│ ├── main.py
│ └── prestart.sh # 可以不要這個文件
└── requirements.txt
Dockerfile內容:
FROM tiangolo/meinheld-gunicorn-flask:python3.9COPY ./requirements.txt /app/requirements.txtRUN pip install --no-cache-dir --upgrade -r /app/requirements.txtCOPY ./app /app
requirements.txt 內容
blinker==1.8.2
click==8.1.7
Flask==3.0.3
importlib_metadata==7.1.0
itsdangerous==2.2.0
Jinja2==3.1.4
MarkupSafe==2.1.5
Werkzeug==3.0.3
zipp==3.18.2
app/main.py 內容
from flask import Flaskapp = Flask(__name__)@app.route('/', methods=['GET'])
def root():return {"Hello": "Flask"}
構建docker鏡像:
cd meinheld-gunicorn-flask-test/
docker build -t meinheld-gunicorn-flask-test:1.0.0 .
運行docker容器:
docker run -d --name meinheld-gunicorn-flask-test -p 8080:80 meinheld-gunicorn-flask-test:1.0.0
二、創建 uvicorn-gunicorn-fastapi-test 目錄,目錄結構為:
uvicorn-gunicorn-fastapi-test
├── Dockerfile
├── app
│ ├── main.py
│ └── prestart.sh # 可以不要這個文件
└── requirements.txt
Dockerfile內容:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.10COPY ./requirements.txt /app/requirements.txtRUN pip install --no-cache-dir --upgrade -r /app/requirements.txtCOPY ./app /app
requirements.txt 內容
annotated-types==0.7.0
anyio==4.3.0
certifi==2024.2.2
click==8.1.7
dnspython==2.6.1
email_validator==2.1.1
exceptiongroup==1.2.1
fastapi==0.111.0
fastapi-cli==0.0.4
h11==0.14.0
httpcore==1.0.5
httptools==0.6.1
httpx==0.27.0
idna==3.7
Jinja2==3.1.4
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
orjson==3.10.3
pydantic==2.7.1
pydantic_core==2.18.2
Pygments==2.18.0
python-dotenv==1.0.1
python-multipart==0.0.9
PyYAML==6.0.1
rich==13.7.1
shellingham==1.5.4
sniffio==1.3.1
starlette==0.37.2
typer==0.12.3
typing_extensions==4.12.0
ujson==5.10.0
uvicorn==0.29.0
uvloop==0.19.0
watchfiles==0.21.0
websockets==12.0
app/main.py 內容
from fastapi import FastAPIapp = FastAPI()@app.get("/")
async def root():return {"Hello": "FastA"}
構建docker鏡像:
cd uvicorn-gunicorn-fastapi-test/
docker build -t uvicorn-gunicorn-fastapi-test:1.0.0 .
運行docker容器:
docker run -d --name uvicorn-gunicorn-fastapi-test -p 8081:80 uvicorn-gunicorn-fastapi-test:1.0.0
性能測試
這里使用ab工具測試并發。先把最大打開文件數調大,執行命令:ulimit -n 65535
# 測試flask,并發3000,連接數10萬
ab -n 100000 -c 3000 http://127.0.0.1:8080/Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requestsServer Software: meinheld/1.0.2
Server Hostname: 127.0.0.1
Server Port: 8080Document Path: /
Document Length: 18 bytesConcurrency Level: 3000
Time taken for tests: 7.209 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 16900000 bytes
HTML transferred: 1800000 bytes
Requests per second: 13871.03 [#/sec] (mean)
Time per request: 216.278 [ms] (mean)
Time per request: 0.072 [ms] (mean, across all concurrent requests)
Transfer rate: 2289.26 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 99 12.5 99 148
Processing: 36 113 20.7 110 346
Waiting: 1 82 18.0 80 317
Total: 109 213 18.1 208 430Percentage of the requests served within a certain time (ms)50% 20866% 21275% 21880% 22590% 23495% 24298% 25299% 258100% 430 (longest request)
下面是fastapi:
# 測試fastapi,并發3000,連接數10萬
ab -n 100000 -c 3000 http://127.0.0.1:8081/Benchmarking 127.0.0.1 (be patient)
Completed 10000 requests
Completed 20000 requests
Completed 30000 requests
Completed 40000 requests
Completed 50000 requests
Completed 60000 requests
Completed 70000 requests
Completed 80000 requests
Completed 90000 requests
Completed 100000 requests
Finished 100000 requestsServer Software: uvicorn
Server Hostname: 127.0.0.1
Server Port: 8081Document Path: /
Document Length: 17 bytesConcurrency Level: 3000
Time taken for tests: 7.198 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 14200000 bytes
HTML transferred: 1700000 bytes
Requests per second: 13892.29 [#/sec] (mean)
Time per request: 215.947 [ms] (mean)
Time per request: 0.072 [ms] (mean, across all concurrent requests)
Transfer rate: 1926.47 [Kbytes/sec] receivedConnection Times (ms)min mean[+/-sd] median max
Connect: 0 88 10.2 88 138
Processing: 44 124 25.8 121 223
Waiting: 1 94 27.8 82 200
Total: 99 213 24.7 208 324Percentage of the requests served within a certain time (ms)50% 20866% 22375% 22980% 23290% 24295% 25698% 27999% 287100% 324 (longest request)
結論:
fastapi(13892.29) 和 flask(13892.29)并發量幾乎一樣,看來 meinheld
的性能確實很高。甚至在 ab 參數 -n 100000 -c 1000
的情況下,多次測試后,fastapi和flask并發數各有勝負。
因此在開發簡單快速的項目時,可以用 meinheld-gunicorn-flask
這套方案。而在需要更多異步編程,需要類型檢查,或者docs(Swagger)文檔時,可以用 uvicorn-gunicorn-fastapi
這套方案。