一、前言
异步编程在构建高性能 Web 应用中起着关键作用,而 FastAPI、Sanic、Tornado 都声称具有卓越的性能。本文将通过性能压测对这些框架与Go的Gin框架进行全面对比,揭示它们之间的差异。
二、环境准备
系统环境配置
编程语言
语言 | 版本 | 官网/Github |
---|---|---|
Python | 3.10.12 | www.python.org/ |
Go | 1.20.5 | go.dev/ |
压测工具
工具 | 介绍 | 官网/Github |
---|---|---|
ab | Apache的压力测试工具,使用简单 | httpd.apache.org/docs/2.4/pr… |
wrk | 高性能多线程压力测试工具 | github.com/wg/wrk |
JMeter | 功能强大的压力/负载测试工具 | github.com/apache/jmet… |
这里选择 wrk 工具进行压测,mac 安装直接通过brew快速安装
brew install wrk
window安装可能要依赖它的子系统才方便安装,或者换成其他的压测工具例如JMeter。
web框架
框架 | 介绍 | 压测版本 | 官网/Github |
---|---|---|---|
FastAPI | 基于Python的高性能web框架 | 0.103.1 | fastapi.tiangolo.com/ |
Sanic | Python的异步web服务器框架 | 23.6.0 | sanic.dev/zh/ |
Tornado | Python的非阻塞式web框架 | 6.3.3 | www.tornadoweb.org/en/stable/ |
Gin | Go语言的web框架 | 1.9.1 | gin-gonic.com/ |
Fiber | todo | todo | gofiber.io/ |
Flask | todo | todo | github.com/pallets/fla… |
Django | todo | todo | www.djangoproject.com/ |
数据库配置
数据库名 | 介绍 | 压测版本 | 依赖库 |
---|---|---|---|
MySQL | 关系型数据库 | 8.0 | sqlalchemy+aiomysql |
Redis | NoSQL数据库 | 7.2 | aioredis |
三、wrk 工具 http压测
FastAPI
普通http请求压测
依赖安装
pip install fastapi==0.103.1
pip install uvicorn==0.23.2
编写测试路由
from fastapi import FastAPI
app = FastAPI(summary="fastapi性能测试")
@app.get(path="/http/fastapi/test")
async def fastapi_test():
return {"code": 0, "message": "fastapi_http_test", "data": {}}
Uvicorn 运行,这里是起四个进程运行部署
uvicorn fastapi_test:app --log-level critical --port 8000 --workers 4
wrk压测
开20个线程,建立500个连接,持续请求30s
wrk -t20 -d30s -c500 http://127.0.0.1:8000/http/fastapi/test
压测结果
➜ ~ wrk -t20 -d30s -c500 http://127.0.0.1:8000/http/fastapi/test
Running 30s test @ http://127.0.0.1:8000/http/fastapi/test
20 threads and 500 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 3.06ms 2.89ms 36.65ms 85.34%
Req/Sec 3.85k 3.15k 41.59k 70.05%
2298746 requests in 30.11s, 383.64MB read
Socket errors: connect 267, read 100, write 0, timeout 0
Requests/sec: 76357.51
Transfer/sec: 12.74MB
Thread Stats 这里是 20、30个压测线程的平均结果指标
-
平均延迟(Avg Latency):每个线程的平均响应延迟
-
标准差(Stdev Latency):每个线程延迟的标准差
-
最大延迟(Max Latency):每个线程遇到的最大延迟
-
延迟分布(+/- Stdev Latency):每个线程延迟分布情况
-
每秒请求数(Req/Sec):每个线程每秒完成的请求数
-
请求数分布(+/- Stdev Req/Sec):每个线程请求数的分布情况
Socket errors: connect 267, read 100, write 0, timeout 0,是压测过程中socket的错误统计
-
connect:连接错误,表示在压测过程中,总共有 267 次连接异常
-
read:读取错误,表示有 100 次读取数据异常
-
write:写入错误,表示有0次写入异常
-
timeout:超时错误,表示有0次超时
MySQL数据查询请求压测
这里在简单试下数据库查询时候的情况
首先先补充下项目依赖
pip install hui-tools[db-orm, db-redis]==0.2.0
hui-tools是我自己开发的一个工具库,欢迎大家一起来贡献。github.com/HuiDBK/py-t…
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @Desc: { fastapi性能测试 }
# @Date: 2023/09/10 12:24
import uvicorn
from fastapi import FastAPI
from py_tools.connections.db.mysql import SQLAlchemyManager, DBManager
app = FastAPI(summary="fastapi性能测试")
async def init_orm():
db_client = SQLAlchemyManager(
host="127.0.0.1",
port=3306,
user="root",
password="123456",
db_name="house_rental"
)
db_client.init_mysql_engine()
DBManager.init_db_client(db_client)
@app.on_event("startup")
async def startup_event():
"""项目启动时准备环境"""
await init_orm()
@app.get(path="/http/fastapi/mysql/test")
async def fastapi_mysql_query_test():
sql = "select id, username, role from user_basic where username='hui'"
ret = await DBManager().run_sql(sql)
column_names = [desc[0] for desc in ret.cursor.description]
result_tuple = ret.fetchone()
user_info = dict(zip(column_names, result_tuple))
return {"code": 0, "message": "fastapi_http_test", "data": {**user_info}}
wrk压测