本内容是对知名性能评测博主 Anton Putra Python (FastAPI) vs Go (Golang) (Round 2) Performance Benchmark vs Go (Golang) (Round 2) Performance Benchmark") 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准
介绍
这是第二轮关于 FastAPI 和 Golang 的对比测试。我几天前运行了前一次的基准测试,到目前为止,我已经收到了 13 个关于 Python 性能改进的 Pull Request。如果你是一名开发者,我建议你先观看之前的基准测试,并对比视频描述中提供的源码和所有的 Pull Request,这样可以帮助你避免我在上一次基准测试中犯的错误。
在第一轮测试中,我们将测量以下指标:
- 使用 90% 分位数 测量客户端每个请求的延迟。
- 使用每秒请求数(Requests Per Second)来衡量吞吐量。
- 应用程序的 CPU 使用率。
- 内存使用情况。
- 可用性或错误率。
- CPU 限制(CPU Throttling)情况。
这些测试将在 AWS 的生产级 Kubernetes 集群中运行。
在第二轮测试中,我们将模拟一个真实的用例:应用程序接收请求后,将数据保存到关系型数据库中,并使用缓存来提高性能。数据库使用 Postgres 17.2,缓存使用 Memcached。如果你感兴趣,可以观看我之前对比 Redis 和 Memcached 的视频结果(结果差距很大)。
所有的基准测试都在 AWS 上运行,使用了不同类型的 EC2 实例。目前,我主要使用基于 ARM 架构的 Graviton 实例,因为它们价格更低。
- Postgres 使用存储优化型的 i8g.large 实例。
- 缓存使用 m8g.large 实例。
- Kubernetes 集群中的监控组件(如 Prometheus 和 Grafana)及负载生成客户端,运行在计算优化型实例上。
- 每个应用程序运行在专用虚拟机上,使用了 m7a.large 实例,并通过 Tolerations 和 Affinity 设置实现隔离(以能够使它们运行在自己专用的虚拟机上面)。
AWS 的费用不低,为了支持我的频道和支付这些基础设施成本,我提供一对一咨询和其他服务。详情请查看视频描述。
第一轮测试(静态内容)
好了,让我们开始第一轮测试。这是第二轮测试了,我建议你先观看使用未经优化的 Python 代码进行的第一次基准测试,然后与这次测试进行对比。在第一轮测试中,我们让应用返回硬编码的对象。
这次测试中:
- 我使用了 FastAPI 推荐的默认 Web 服务器 Uvicorn,并配置了两个工作线程(workers)。
- 端点使用了异步处理(Async Handler)。
虽然在第一次基准测试中性能稍好,但最终还是失败了并恢复运行。
在这次测试中,性能稍微更稳定,但只能达到 每秒 11,000 请求。虽然差距不是很大,但对性能还是有影响。在运行到每秒约 11,000 请求时,由于 CPU 限制,开始出现失败,延迟大幅上升,可用性下降。
我原本期望经过这些优化和收到的众多 Pull Request(你可以在视频描述中找到所有这些 Pull Request),性能会更好。不过,我会继续运行测试,直到 Go 应用程序也开始出现失败。
Golang 的表现依旧出色,可以达到 每秒 60,000 到 65,000 请求,这是非常不错的性能。虽然不是最顶尖的,但一些语言(比如 Rust 和 Zig)在类似测试中可以达到 每秒 100,000 请求。但无论如何,在这次测试中,Go 的效率远远高于 FastAPI。
接下来,我们打开每个测试指标的图表:
每秒请求数(Requests Per Second)
- Python 达到了 每秒 11,000 请求,而 Go 达到了 每秒 66,000 请求。
延迟(Latency)
- 对于面向客户端的应用程序来说,延迟是最重要的指标之一,而 Go 在这一点上表现得更好。
CPU 使用率
- FastAPI 很快耗尽了所有可用 CPU。
- 可用性(Availability)
- 内存使用(Memory Usage)
- CPU 限制(CPU Throttling)
在这次测试中,FastAPI 的表现并不好。但我会继续测试其他 Python 框架,例如 Starlette(FastAPI 的底层框架),或者直接创建一个 ASGI Python 应用,看看能否接近 Go 应用的性能。
第二轮测试(Postgres + Memcached)
第二轮测试主要针对真实场景的改进,结果确实在真实用例中有显著提升。在这个测试中,应用程序需要:
- 解析请求体。
- 将记录插入到关系型数据库中。
- 将数据缓存到 Redis 或 Memcached 中。
如果你想改进你的 Python 应用程序,我建议对比两种实现,并查看仪表板上的性能差异。
在之前的基准测试中,FastAPI 只能达到 每秒 750 请求。在这次改进后,性能提升到了 每秒 2,500 请求。相比之前的测试,这是一个巨大的改进,但仍远不及 Go 应用。
在这次测试中,我们还测量了以下指标的延迟:
- 数据库插入操作的延迟。
- 保存数据到缓存的函数调用延迟。
- 总体 POST 请求的延迟。
虽然 Python 表现比之前好了许多,但在性能上仍然远不及 Go 应用。这次测试中,我收到了很多 Pull Request,但这已经是目前的最佳性能了。我觉得需要尝试其他 Python 框架,寻找能够接近 Go 应用性能的解决方案。
未来,我将只测试 Python 框架,比如 Django、Flask 和 FastAPI。
接下来打开每个测试指标的图表:
- 每秒请求数(Requests Per Second)
- FastAPI 最高达到了 每秒 2,600 请求,而 Go 达到了 每秒 20,000 请求。
- 在之前的测试中,Go 的性能受限于 Memcached 的连接数设置。这次测试中,我增加了闲置连接数限制,所以 Go 能够充分利用 CPU,达到更高的请求数。
- 总体 POST 请求延迟(Overall Latency for POST Requests)
- 数据库操作延迟(Database Operation Latency)
- 缓存延迟(Cache Latency)
- CPU 使用率(CPU Usage)
- Postgres 和 Memcached 的 CPU 使用率
- 从图中可以看到,对于相同数量的数据库和缓存请求,缓存只需要很少的资源。因此,使用缓存不仅可以显著提高应用性能,还可以通过减少资源使用来降低基础设施成本。
- Postgres 连接池(Connection Pool)
- 每个应用程序创建并维护了一个最大连接数为 500 的 Postgres 连接池。
- 内存使用(Memory Usage)
总结
我将继续寻找并测试更快的 Python 框架。如果你感兴趣,可以查看我其他的基准测试视频。感谢观看,我们下次见!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。