本内容是对知名性能评测博主 Anton Putra Python (FastAPI) vs Go (Golang) (Round 2) Performance Benchmark vs Go (Golang) (Round 2) Performance Benchmark") 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准

介绍

这是第二轮关于 FastAPIGolang 的对比测试。我几天前运行了前一次的基准测试,到目前为止,我已经收到了 13 个关于 Python 性能改进的 Pull Request。如果你是一名开发者,我建议你先观看之前的基准测试,并对比视频描述中提供的源码和所有的 Pull Request,这样可以帮助你避免我在上一次基准测试中犯的错误。

在第一轮测试中,我们将测量以下指标:

  1. 使用 90% 分位数 测量客户端每个请求的延迟。
  2. 使用每秒请求数(Requests Per Second)来衡量吞吐量。
  3. 应用程序的 CPU 使用率。
  4. 内存使用情况。
  5. 可用性或错误率。
  6. CPU 限制(CPU Throttling)情况。
    这些测试将在 AWS 的生产级 Kubernetes 集群中运行。

在第二轮测试中,我们将模拟一个真实的用例:应用程序接收请求后,将数据保存到关系型数据库中,并使用缓存来提高性能。数据库使用 Postgres 17.2,缓存使用 Memcached。如果你感兴趣,可以观看我之前对比 RedisMemcached 的视频结果(结果差距很大)。

所有的基准测试都在 AWS 上运行,使用了不同类型的 EC2 实例。目前,我主要使用基于 ARM 架构的 Graviton 实例,因为它们价格更低。

  • Postgres 使用存储优化型的 i8g.large 实例。
  • 缓存使用 m8g.large 实例。
  • Kubernetes 集群中的监控组件(如 PrometheusGrafana)及负载生成客户端,运行在计算优化型实例上。
  • 每个应用程序运行在专用虚拟机上,使用了 m7a.large 实例,并通过 TolerationsAffinity 设置实现隔离(以能够使它们运行在自己专用的虚拟机上面)。

AWS 的费用不低,为了支持我的频道和支付这些基础设施成本,我提供一对一咨询和其他服务。详情请查看视频描述。


第一轮测试(静态内容)

好了,让我们开始第一轮测试。这是第二轮测试了,我建议你先观看使用未经优化的 Python 代码进行的第一次基准测试,然后与这次测试进行对比。在第一轮测试中,我们让应用返回硬编码的对象。

这次测试中:

  • 我使用了 FastAPI 推荐的默认 Web 服务器 Uvicorn,并配置了两个工作线程(workers)。
  • 端点使用了异步处理(Async Handler)。

虽然在第一次基准测试中性能稍好,但最终还是失败了并恢复运行。

在这次测试中,性能稍微更稳定,但只能达到 每秒 11,000 请求。虽然差距不是很大,但对性能还是有影响。在运行到每秒约 11,000 请求时,由于 CPU 限制,开始出现失败,延迟大幅上升,可用性下降。

我原本期望经过这些优化和收到的众多 Pull Request(你可以在视频描述中找到所有这些 Pull Request),性能会更好。不过,我会继续运行测试,直到 Go 应用程序也开始出现失败。

Golang 的表现依旧出色,可以达到 每秒 60,000 到 65,000 请求,这是非常不错的性能。虽然不是最顶尖的,但一些语言(比如 RustZig)在类似测试中可以达到 每秒 100,000 请求。但无论如何,在这次测试中,Go 的效率远远高于 FastAPI。

接下来,我们打开每个测试指标的图表:

  1. 每秒请求数(Requests Per Second)

    • Python 达到了 每秒 11,000 请求,而 Go 达到了 每秒 66,000 请求

  1. 延迟(Latency)

    • 对于面向客户端的应用程序来说,延迟是最重要的指标之一,而 Go 在这一点上表现得更好。

  1. CPU 使用率

    • FastAPI 很快耗尽了所有可用 CPU。

  1. 可用性(Availability)

  1. 内存使用(Memory Usage)

  1. CPU 限制(CPU Throttling)

在这次测试中,FastAPI 的表现并不好。但我会继续测试其他 Python 框架,例如 Starlette(FastAPI 的底层框架),或者直接创建一个 ASGI Python 应用,看看能否接近 Go 应用的性能。


第二轮测试(Postgres + Memcached)

第二轮测试主要针对真实场景的改进,结果确实在真实用例中有显著提升。在这个测试中,应用程序需要:

  1. 解析请求体。
  2. 将记录插入到关系型数据库中。
  3. 将数据缓存到 Redis 或 Memcached 中。

如果你想改进你的 Python 应用程序,我建议对比两种实现,并查看仪表板上的性能差异。

在之前的基准测试中,FastAPI 只能达到 每秒 750 请求。在这次改进后,性能提升到了 每秒 2,500 请求。相比之前的测试,这是一个巨大的改进,但仍远不及 Go 应用。

在这次测试中,我们还测量了以下指标的延迟:

  • 数据库插入操作的延迟。
  • 保存数据到缓存的函数调用延迟。
  • 总体 POST 请求的延迟。

虽然 Python 表现比之前好了许多,但在性能上仍然远不及 Go 应用。这次测试中,我收到了很多 Pull Request,但这已经是目前的最佳性能了。我觉得需要尝试其他 Python 框架,寻找能够接近 Go 应用性能的解决方案。

未来,我将只测试 Python 框架,比如 DjangoFlaskFastAPI

接下来打开每个测试指标的图表:

  1. 每秒请求数(Requests Per Second)

  • FastAPI 最高达到了 每秒 2,600 请求,而 Go 达到了 每秒 20,000 请求
  • 在之前的测试中,Go 的性能受限于 Memcached 的连接数设置。这次测试中,我增加了闲置连接数限制,所以 Go 能够充分利用 CPU,达到更高的请求数。
  1. 总体 POST 请求延迟(Overall Latency for POST Requests)

  1. 数据库操作延迟(Database Operation Latency)

  1. 缓存延迟(Cache Latency)

  1. CPU 使用率(CPU Usage)

  1. Postgres 和 Memcached 的 CPU 使用率

  • 从图中可以看到,对于相同数量的数据库和缓存请求,缓存只需要很少的资源。因此,使用缓存不仅可以显著提高应用性能,还可以通过减少资源使用来降低基础设施成本。
  1. Postgres 连接池(Connection Pool)

  • 每个应用程序创建并维护了一个最大连接数为 500 的 Postgres 连接池。
  1. 内存使用(Memory Usage)


总结

我将继续寻找并测试更快的 Python 框架。如果你感兴趣,可以查看我其他的基准测试视频。感谢观看,我们下次见!


好文收藏
38 声望6 粉丝

好文收集