本内容是对知名性能评测博主 Anton Putra Go (Golang) Performance Benchmark (gnet vs fiber vs fasthttp vs net/http) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准
在本内容中,我们将尝试寻找最快的 Go Web 框架。我们会对 Go 标准库、fasthttp、Fiber 和 gNet 框架进行对比。
在第一个测试中,我们将仅比较这些框架本身。我们从延迟测试开始,延迟从客户端侧进行测量。我认为延迟是衡量任何框架最重要的指标之一。接着,我们会通过每秒请求数来衡量每个框架的吞吐量。
我们还将测量 CPU 使用率、内存使用率、可用性(或错误率),以及 CPU 限流情况,因为我们会在 Kubernetes 中运行这些应用程序。
在第二个测试中,我会添加一个 PostgreSQL 数据库,并为每个应用程序添加 Prometheus 指标,以测量插入操作的延迟。同时我们还会测量连接池大小以及数据库本身的 CPU 使用情况。
我认为我在其中一个框架中发现了一个重大限制。
我使用 AWS 来运行这些测试。我创建了一个 EKS 集群,并包含两个实例组。我使用 4xlarge Graviton 实例来部署我的监控组件,并为每个应用程序使用 large 实例,确保每个应用程序都运行在独立的虚拟机上。
在第二个测试中,我将 PostgreSQL 部署在一个 2xlarge 实例上,该实例配备了 8 个 CPU 和 64GB 内存,并使用 pgTune 来优化数据库性能。
好了,让我们开始运行测试。
就像我在很多其他测试中那样,在这次测试中,Go 标准库一开始就展现出了最低延迟。但它同时也具有最高的 CPU 使用率。
当每秒请求达到约 15,000 次、CPU 使用率达到 32% 左右时,标准库失去了它的优势,变成了最慢的框架。因此,如果你使用标准库,请注意这个 CPU 使用阈值,并进行横向扩展。
另一边是 Fiber 和 fasthttp,它们的表现非常接近。这是因为 Fiber 是构建在 fasthttp 之上的一个框架。fasthttp 本身并没有一个用户友好的 API,而 Fiber 则是在 fasthttp 的基础上包装,提供了更好用的 API 和中间件。
gNet 被认为是最快的框架,至少从我看到的基准测试来看是这样,但它的 API 非常底层,几乎没有文档。不过,它具有极小的内存占用和最低的 CPU 使用率,最终有潜力实现最高的吞吐量。
当每秒请求达到约 55,000 次时,你会开始注意到标准库已经明显落后于其他所有框架;这与我在 AWS 上运行的所有使用 Go 的基准测试结果都非常一致。同时你也可以注意到,在高负载下,gNet 拥有目前最低的延迟。
当每秒请求达到约 90,000 次时,Fiber 和标准库的健康检查开始失败。在 Kubernetes 中,如果 Pod 失败得太快,就会进入 CrashLoopBackOff 状态。在生产中,为了恢复,你需要将容量加倍,然后根据负载调整。
所以现在剩下 fasthttp 和 gNet 争夺最快框架的头衔。
看起来 fasthttp 在最终阶段更为稳定,能够处理超过 100,000 次每秒的请求,这与标准库相比是一个巨大的差距,而 gNet 稍微落后,处理能力为约 98,000 次每秒。
好了,现在让我打开每一个图表,展示整个测试的持续时间。
首先是每秒请求数图表;
接着是 GET 请求的延迟,使用的是第 99 百分位;
然后是 CPU 使用率;
可用性图表;
内存使用率;
最后是 CPU 限流图表:
如预期所示,在这个测试中,标准库是最慢的,而 fasthttp 实际上比其他任何框架表现都更好。
在第二个测试中,当客户端发送一个带有 JSON 负载的 POST 请求时,每个应用程序需要解析它,将其转换为 Go 结构体,然后使用 PostgreSQL 驱动将其保存到数据库中。
在这里,我们测量的是应用程序将新记录插入数据库时的延迟。源代码已上传到我的公共 GitHub 仓库,如果你能改进它,欢迎尝试。
在这个测试中,我还使用了 PostgreSQL Exporter 来跟踪每个应用程序创建的连接池大小,并在 gNet 中发现了一个重大问题。我确实启用了多核支持,因为我们运行的是一个拥有两个 CPU 的虚拟机。gNet 创建了两个事件循环。
例如在我的 Mac 上,有 10 个 CPU 核心,它就会创建 10 个事件循环。最好是运行与 CPU 核心数相同数量的线程或进程,这与 Ruby on Rails 等其他框架类似。
然而,连接池是受线程数限制的。所以虽然每个应用程序的连接上限都是 100,但 gNet 只创建与事件循环数相同的连接数。也许有办法修改这个行为,但官方几乎没有任何文档。
因此,数据库连接数会成为 gNet 的限制因素。这不仅会影响数据库驱动,还可能影响 AWS SDK 以及它能够创建的连接数。
在这个测试中,我为 PostgreSQL 使用了 2xlarge 实例,实际上这成为了瓶颈。我可能会在未来的测试中使用更大的实例,只是成本会变得非常高。
好了,现在让我展示每个图表的完整测试周期。
首先是每秒请求数图表。由于 gNet 的数据库连接池太小,它远远落后于其他应用程序;
接下来是 POST 请求的整体延迟;
然后是数据库插入延迟。就像之前的测试一样,标准库的表现优于其他框架;
接着是 CPU 使用率;
可用性图表;
PostgreSQL 数据库的 CPU 使用率;
连接池大小;
以及内存使用率:
看起来,在所有测试中,标准库都有最好的延迟性能,但同时也有最高的 CPU 使用率。是否选择它,就看你更重视延迟还是吞吐量了。
感谢观看,我频道上还有其他你可能感兴趣的基准测试。谢谢,我们下个视频再见。