2021 年,用 Python 部署异步网络服务的最佳实践是什么?
先说几句题外话,前两天看见一个帖子,提到异步框架的,里面很多人推荐 fastapi 。我个人说来很惭愧,学习 python 的 web 框架,入门是 flask,异步是 aiohttp,一直与 django 和 fastapi 这类主流的、用的人比较多的框架无缘。
所以这次也是想学习一下 fastapi,看看相对于一直使用的原生 aiohttp 有什么区别。
根据我个人理解,异步从 python3.4 版本提出以来,现在已经不是像 3.6 版本时候那样大家都不会用,现在用异步的人应该越来越多了。目前主流不管是公司内部服务,还是生产级服务,如果上 python 的话,如果要用异步的话,应该是很多人使用 django 的 asgi,一些人使用 fastapi,几乎没有人使用 aiohttp 这样。tornado 我不太了解,因为我最初接触异步是 3.5 时代,彼时 tornado 的异步是用猴子补丁实现的,所以一直也没做接触,不知道现在是怎么样了。
使用异步框架当然第一步还是看性能,我去 fastapi 官网看了一下教学,教学写的很友好,直接就推荐了 fastapi+uvicorn 的部署方案。
官网上写了 fastapi 是最快的框架之一,我们都知道 python 异步刚出的时候有很多昙花一现的框架,比如 Vibora,japronto 这些,性能做的都非常夸张,单例可以达到十万 qps,实际上是用 py 胶水封装了一下 c 框架而已,性能高也很正常,可惜这些开发社区做了 demo 出来以后都不怎么活跃了,bug 不修,没法投入生产级。
倒是 aiohttp 这个一上来看起来就很弱的,表现也不怎么亮眼的,一直更新到现在,投入生产级也完全没问题了,说句题外话,我个人使用起来主要优势就是用的熟,想实现什么效果几乎以前都做过,很快都能找到解决方案,所以学习 fastapi 对我来说倒是要考虑学习成本问题。
=====================================================================
说回正题,关于压力测试,我在虚拟机上用 wrk 进行压测,测试结果 fastapi 其实表现并不好,想问一下各位 fastapi 用的比较熟练的大佬,是我部署错误,还是它的性能表现就是这样的。
另外想问一下切换到生产级服务的话,fastapi 这条路线目前坑度怎么样,比如 web 部署里的一些常用插件,cors,basic auth,jwt 等等,还有中间件开发,支持 ws 协议等等,目前这些坑都踩的差不多了吗?这个框架从名字来看就可以看出是为 api 设计的,如果用来一体化部署 spa 之类的,有额外的坑吗?
谢谢大家
=====================================================================
附一些压测数据
#笔记本随手测一下,虚拟机给了 8 核心,所以用 16 线程 500 并发进行测试 # fastapi + uvicorn 部署,单进程 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 20.88ms 3.51ms 50.90ms 95.22% Req/Sec 0.96k 66.29 1.21k 83.54% 95737 requests in 20.01s, 13.70MB read Requests/sec: 4784.35 Transfer/sec: 700.83KB # aiohttp + 自带服务部署,单进程 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 12.90ms 2.94ms 58.01ms 94.81% Req/Sec 1.57k 156.69 1.82k 80.90% 156446 requests in 20.05s, 24.32MB read Requests/sec: 7803.19 Transfer/sec: 1.21MB # aiohttp + gunicorn(uvloop 模式) ,单进程 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 6.12ms 1.08ms 23.27ms 90.35% Req/Sec 3.28k 216.93 5.05k 72.67% 327908 requests in 20.10s, 50.97MB read Requests/sec: 16315.63 Transfer/sec: 2.54MB
一般来说这些框架都会自带一个 web 服务,可以用来做测试什么的,一般因为稳定性,性能等等原因,都不会用在生产环境部署。但是根据这个单线程测试,fastapi 实际上单进程只有 aiohttp 的 60%,如果用 gunicorn 部署的话(值得吐槽的是 gunicorn 似乎本身也是 python 中不算快的部署方式。。),fastapi+uvicorn 的组合只有 aiohttp+gunicorn 25%左右的性能
然后是多进程 prefork 测试,采用 8 线程部署服务。
# fastapi 8 线程 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 6.53ms 1.94ms 33.58ms 79.44% Req/Sec 3.09k 476.62 4.02k 60.60% 307858 requests in 20.07s, 28.48MB read Requests/sec: 15341.09 Transfer/sec: 1.42MB # fastapi 增大 echo 报文长度 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 9.56ms 6.59ms 51.53ms 61.89% Req/Sec 2.18k 1.18k 6.39k 87.10% 217184 requests in 20.05s, 24.85MB read Requests/sec: 10834.00 Transfer/sec: 1.24MB # aiohttp 8 线程 Running 20s test @ http://127.0.0.1:8000 16 threads and 500 connections Thread Stats Avg Stdev Max +/- Stdev Latency 2.77ms 1.34ms 16.60ms 65.92% Req/Sec 7.30k 2.28k 19.59k 73.53% 726936 requests in 20.10s, 123.40MB read Requests/sec: 36170.63 Transfer/sec: 6.14MB
可以看到同样地,fastapi 性能只有 aiohttp 的三成左右。另外值得吐槽的是使用长报文测试下,fastapi 的 echo 性能衰退又有点厉害啊,直接掉三成。