本内容是对知名性能评测博主 Anton Putra Elixir vs Go (Golang) Performance Benchmark (Round 2) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准
这是第二轮关于 Elixir 和 Go 的对比测试。我收到了一份来自 Elixir 创作者的 Pull Request ,并且我认为有必要分享他所做的一些改进。他还表示,在 Kubernetes 环境下比较这两种语言是没问题的,我只需要为应用程序分配整个 VM(虚拟机)。因此,我使用了 Tolerations(容忍度)和 Affinity(亲和性)来实现这一点。
第一轮测试
在第一轮测试中,我们的目标是返回硬编码的对象给客户端,并测量 P90(90% 分位数)的延迟。同时,我们还会通过每秒请求数(Requests per Second,简称 RPS)的指标来衡量吞吐量,并记录以下关键数据:
- CPU 使用率
- 内存使用率
- 可用性(错误率)
- CPU 限流(Throttling)
由于我们会将这两个应用程序部署到 AWS 上的生产级 Kubernetes 集群,因此这些指标至关重要。这次 Pull Request 带来了一些改进,我建议你也可以与之前的基准测试进行对比。
第二轮测试
第二轮测试模拟了一个更接近实际应用场景的案例:
- 当应用程序接收到 POST 请求时,它会解析请求体,并将记录插入到关系型数据库中,然后返回数据库生成的 ID 给客户端。
- 除了前述的性能指标,我们还会额外测量:
- 数据库操作的延迟(通过内部监测每个应用程序)
- 数据库的 CPU 使用率(使用 Node Exporter 进行监测)
- 应用程序创建的数据库连接池大小(使用 Postgres Prometheus Exporter 监测)
所有的基准测试都在 AWS 上运行。在本次测试中,我使用了一台 存储优化型 Graviton2 xlarge 实例 作为数据库服务器。不过,我认为未来可能需要升级它。此外,我还创建了一个 EKS 集群,其中:
- 计算优化型节点 用于 Prometheus、Grafana 和 客户端 生成负载。
- M7A Large 实例 用于运行应用程序,每个应用程序都部署在自己的 EC2 实例上。
AWS 并不便宜,为了支持我的频道,我提供 一对一咨询服务。如果你感兴趣,可以在视频描述中找到更多信息。
开始执行第一轮测试
整个测试持续 1.5 小时,但我会将其压缩到 1.5 分钟 的展示时间。此外,你可以在此处找到 完整的源代码。
第一轮测试结果
1. 每秒请求数(Requests per Second, RPS)
- Elixir 处理了 20,000 RPS,比之前的基准测试提升了 2,000 RPS,可以看到一定的性能提升。
- Go 预期达到了 60,000 RPS,依然领先。
2. 客户端延迟
- Elixir 的延迟相比之前的基准测试略有降低,延迟越低越好。
- 但它仍然远远落后于 Go 的性能。
3. CPU 使用率
- CPU 使用率越高,吞吐量越低,延迟越高,这并不意外。
- Elixir 在这个测试中表现不如 Go,至少在这个特定的工作负载下。
4. 可用性(错误率)
- 可用性 通过每秒错误数来衡量,错误数越低,代表系统越稳定。
- 这个图表展示的是每秒错误数,错误数越高,代表可用性下降。
5. 内存使用情况
- 之前已经预料到,在 Go 崩溃之前,它的内存使用率会不断上升。
6. CPU 限流(CPU Throttling)
- Elixir 的 CPU Throttling 现象更严重,因为它更早达到 CPU 使用率的上限,相比之下 Go 应用程序的 CPU 资源管理更高效。
这一轮静态测试的结果可以作为后续测试的基准。
开始执行第二轮测试
这轮测试的展示时间同样压缩到了 1.5 分钟。
第二轮测试结果
1. 每秒请求数(Requests per Second, RPS)
- 这次测试中,相较于之前的基准测试,并没有明显的提升,甚至可以说有轻微的下降。
- Go 在两次测试中都稳定在 22,000 RPS。
2. POST 请求延迟
- Elixir 的延迟相比之前的测试有所降低,表现略有提升,但仍然不及 Go。
3. 数据库插入延迟
- 大部分请求的延迟都来自数据库操作,这在预期之内。
- 我按照建议创建了 4 个数据库连接池,每个池有 125 个连接。
4. CPU 使用率
- 这里没有太多意外的发现。
- 未来我可能需要增加数据库连接池的大小,以便让 CPU 资源利用率达到更高水平。
- 数据库连接池大小 和 网络 I/O 通常是瓶颈,连接数越多,吞吐量越大。但同时,也需要监控数据库本身的健康状况,确保它不会成为新的瓶颈。
5. 可用性
- 这次测试中,我将超时时间增加到 5 秒,因此没有看到错误。
6. PostgreSQL 数据库的 CPU 使用
- 上一次测试 使用的是 AMD 处理器,这次测试采用的是 Graviton4 第四代处理器。
7. 数据库连接池大小
- Elixir 应用在启动时会立即创建 500 个数据库连接。
- Go 则会根据负载逐步增加连接数。
- 我认为未来可能需要将连接数增加至 1,000,以进一步优化性能。
- 值得一提的是,Amazon RDS 默认的最大连接数是 5,000,所以应该不会有太大问题。
8. 内存使用情况
- 如果你有更好的优化方案,欢迎提交 Pull Request!
- 我总是愿意承认自己的错误,并在合理的情况下重新运行测试。