在 Raygun ,追求极致性能已然成为公司文化的一部分。在发布本文时,我们在 Twitter 上被问到一个问题,为什么我们会使用 Nginx 作为 Raygun API 应用程序的代理。
回答是,这是微软推荐的方法。事实证明,自.NET Core 2.1 发布以来,情况并非如此。从我们第一次使用.NET Core 1.0 到现在,Kestrel 已经成熟很多,并且自.NET Core 2.1 发行以来,微软的安全专家们对 Kestrel 在前端服务的表现感到十分满意。
1. 为什么移除或使用 Nginx?
在某些情况下,大家仍然会坚持使用 Nginx 这样的代理,我会在下面给你列举出来。对于 Raygun,我们的 API 服务器仅托管了一个应用程序,然后仅通过负载均衡设备公开到互联网。这意味着对端口共享的限制并不适用于我们,开放给外部的服务已经被最小化了。
我们可能要使用代理的一些原因(来自微软的一篇博文),列举如下:
- 限制其托管应用程序的对外公开部分
- 提供附加的配置和防御层
- 方便与现有基础架构更好地集成
- 简化负载平衡和安全通信(HTTPS)配置。只有反向代理服务器需要 X.509 证书,并且该服务器可以使用 HTTP 与内部网络上的应用服务器进行通信。
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#when-to-use-kestrel-with-a-reverse-proxy
2. 移除 Nginx 后的业务表现
对于我们的 API 节点,从配置中删除 Nginx 可以使我们处理更多的请求而无需额外费用。
通过负载测试,我们还发现请求的平均响应时间和第 99 百分位响应时间得到显著改善。这意味着我们的客户对 API 服务的请求更快,并允许他们在单位时间内发送更多数据。
自从将新的服务器配置投入生产以来,我们的负载均衡设备报告 5xx 错误也大大减少了。现在,我们可以支撑处理更高的客户端负载,而且用户遇到的错误问题也更少了。
3. 我们如何测试.NET Core 性能
我们在亚马逊的 AWS c5.large 实例 Ubuntu 18.04 环境下进行了测试。基准服务器运行了 Nginx 和 Kestrel Web 服务,Nginx 作为 Kestrel Web 服务代理;作为对比,在另一台服务器上,服务请求直接由 Kestrel 处理。
我们使用 Apache JMeter 将 Raygun Crash Reporting 样本有效负载发布到服务 API。JMeter 可以模拟非常高的并发请求负载。我们对此不断进行调整,让每台服务器都最大程度地利用 CPU,逼近服务过载即将不能支撑处理所有请求的极限(但是仍然保证请求的成功率为 100%)。
https://raygun.com/platform/crash-reporting
使用 JMeter 运行多次测试,每个测试持续 10 分钟,每次测试结束时生成保存测试摘要报告。
最后,我们将多次测试的结果取平均值,最终得出下面的测试结果。
4. 移除 Nginx 后的结果展示
响应时间(毫秒)
平均响应时间(该值越小性能越好)从 1.2ms 减少到 0.8ms,相当于降低了 33%;第 99 百分位响应时间从 6ms 减少到 4ms,相当于降低了 33%。
TPS
TPS(该值越大性能越好)从 3783 个增加到 5461 个,相当于提升了 44%。
5. 在生产环境运行新配置服务的观察结果
内存使用情况
使用 Nginx 运行该服务实例时,每个实例使用的平均内存非常一致,内存使用率在 13%和 16%之间。
自从删除 Nginx 以来,我们已经看到服务进程的内存使用率变大,在 15%到 30%之间,平均值趋近为 22%。我们确信这是由于 Nginx 限制了 Kestrel 处理的请求数量。
因此,Kestrel 在高并发下始终会以一定的速率处理请求,这意味着内存使用量几乎没有很大变化。消除这一瓶颈后,由于 Kestrel 会处理数量不等的请求,我们现在可以看到更多的内存使用和变化情况。
Nginx + Kestrel
Kestral only
平均活跃节点数
活跃节点的平均数量从 5.35 下降到 4.66。现在,我们可以看到相当长的时间内仅仅运行着四个服务器;而在同一时段的高峰时期,相比之前使用 Nginx,我们同样运行着更少的服务器。
Nginx + Kestrel
Kestral only
负载均衡设备的 5xx 错误率
一段时间以来,我们发现通过负载均衡设备统计的信息报告中,5xx 错误率很高,如下图所示。这些错误并不是来自我们应用程序,而且在 Raygun 也没有对其认定为故障并进行报告。
原来,这些错误来自 Nginx,并且通过删除此代理,我们现在可以更好地处理满负载,而且大大减少了故障的发生。
总体而言,由于我们服务器处理的请求量很大,即使是以下较高的数量也仅占我们处理的总请求量的很小一部分。注意到通过删除 Nginx 层可以得到显著的性能提升,这一点是值得肯定的。我们并不是对 Nginx 进行批评和否定,当然也有可能是我们 Nginx 最终的配置问题,但是,简化配置似乎可以更好地解决这个问题。
6. 总结
敢质疑关于性能问题的原始假设非常棒,在 Raygun,我们追根溯源,最终发现问题以及解决了问题。随着我们基础架构的不断拓展,能够以更低成本处理更多的数据,这给我们带来了一些可观的业务收益,而这一切都始于有人问了一个简单的问题:“为什么?”
值得注意的是,.NET 团队一直在努力改善和优化性能。尽管.NET 5 计划于今年 11 月发布,但目前已经有很多重要更新可以使用了。