转自:http://www.servicemesh.cn/?/article/45
作者:Turgay Çelik
翻译:钟毅(Drew Zhong)
原文:Comparing API Gateway Performances: NGINX vs. ZUUL vs. Spring Cloud Gateway vs. Linkerd
不管是从团队人数,还是从公司产品的特性的角度来看,我们 OpsGenie 都处于快速成长的过程中。举例来说,仅就去年一年,我们的工程师团队人数由15人增长到50人。同时我们遵从了 Two Pizza team rule ,将工程师团队每8人分成一组,以更好地适应团队总人数的迅速增长。
你可能也猜到,目前 OpsGenie 的产品已经有点类似巨石应用了。由于多个团队共同开发维护同一个产品 以及 CI/CD ( Continuous Integration/Continuous Delivery ) 流程等原因,产品的开发和维护已经变得极具挑战。因此,我们不得不紧随当下的趋势,将巨石应用向分布式架构转变。读者可以从 Martin Fowler 的文章中,了解更多关于微服务架构和它的优点。
在对微服务概念的实践中,有一些值得推荐的架构模式。而 API 网关就是这些模式中的一个。简单来说,API 网关就是所有客户端的统一入口。它通过两种方式来处理客户端请求:一是作为代理,将请求路由给某一个特定的服务;二是将请求分散给多个服务。 API 网关是微服务框架的一个很好的开端,因为一个巨石应用微服务化后能够得到多个不同的服务,而API 网关能将特定的请求路由给特定的服务。
实际上,API 网关对我们来说并不是一个新的概念。我们用 Nginx 来作为我们巨石应用的 API 网关已经很长一段时间了,但是既然我们已经打算向微服务转型,那我们就不得不重新评估 Nginx 是不是一个好的选择。性能、可扩展性以及像限流等其它特性,都是我们需要考虑的。当然网关的性能,尤其是在高并发场景下能否满足我们的需求,才是我们最在意的。
在本篇博文中,我们将阐述如何搭建我们的测试环境,并比较 Zuul 1、Nginx、Spring Cloud Gateway 和 Linkerd。事实上,我们还有像 Lyft 的 Envoy 和 UnderTow 等其它备用方案。我们会对这些工具进行同样的测试,然后在以后的博文中再分享结果。
Zuul 1 对我们团队而言是一个不错的选择。因为它是由 Java 开发的,而且也完美兼容 Spring 框架。目前,已经有一些博客是进行 Zuul 和 Nginx 的比较的。但我们同时也想要比较 Spring Cloud 网关和 Linkerd,另外,我们也希望进行更一步的压力测试。所以,我们决定搭建我们自己的环境来进行测试。
为了客观地评估各个 API 网关自身的性能,我们创建了一个独立于 OpsGenie 产品之外的 隔离的测试环境。我们使用 Apache Http Server Benchmarking tool — ab 来搭建我们的测试环境。
首先,我们根据 Nginx 的官方文档,在 AWS EC2 t2.micro 实例上部署 Nginx 。这是我们的初始测试环境。然后我们在这个环境之上,又部署了 Zuul 和 Spring Cloud Gateway。Nginx web 服务器中放置了一些静态资源,然后我们分别在 Nginx、Zuul 和 Spring Cloud Gateway 上定义一些指向 web 服务器的反向代理。然后我们将另一个 t2.micro EC2 作为客户端,来发起一些请求。
图中带箭头的虚线就是我们测试用的路径。主要有以下五种方式:
· 直连
· 通过 Nginx 反向代理请求
· 通过 Zuul 请求
· 通过 Spring Cloud Gateway 请求
· 通过 Linkerd 请求
鉴于读者往往更关心结果,所以接下来我们会先给出测试结果,然后再进行详细的解释。
Benchmark性能总数
测试策略
我们使用 Apache 的 HTTP 服务器 Benchmark 工具。每一轮,我们用200个线进行10000次请求。
ab -n 10000 -c 200 HTTP://<server-address>/<path to resource>
我们在三种不同配置的 AWS EC2 上进行测试。为了更好地说明真实的请求, 我们对每一轮测试都进行了细分:
· 为了了解代理本身所需要的开销,我们首先对直连方式进行了额外的单独测试。但介于直连并不是我们的待选方案,因此后面的几轮就不再对直连进行测试。
· 介于 Spring Cloud Gateway 至今还没有正式发版,因此我们只会在最后一轮对它进行测试。
· Zuul 在调用过一次之后的性能表现会更好。我们认为这是 JIT 优化 (Just In Time) 的效果。所以我们形象地将 Zuul 的第一次运行称作是“热身”。当然,下面各个表中的数值都是 Zuul“热身”之后的性能。
· 我们都知道,Linkerd 是一种很吃资源的代理方式,因此我们就只在最后一轮,即性能配置最佳的方案中才会进行对它的比较。
测试用配置
T2.Micro --单核、1g内存:我们在这个配置上进行直连、Nginx 反向代理和 Zuul (热身后)三种代理方式的测试 M4.Large --双核、8g内存:我们在这个配置上进行 Nginx 反向代理和 Zuul (热身后)两种代理方式的测试 M4.2xLarge --八核、32g内存:我们在这个配置上进行 Nginx 反向代理、Zuul(热身后)、Spring Cloud Gateway 和 Linkerd 四种代理方式的测试
测试结果
以下是性能测试结果的概要:
测试的细节
直连
首先,我们在不使用任何代理的情况下直接访问静态资源。结果如下图所示。每次请求所需要的响应时间是30ms。
通过 Nginx 反向代理连接
在第二次测试中,我们通过Nginx反向代理访问资源。每次请求的响应时间为40ms。我们发现,和上一部分不使用任何代理的直连方式相比,Nginx反向代理平均增加了33%的耗时。
通过 Zuul 反向代理的连接
首先,我们创建了一个如下 Spring Boot 应用程序:
以下是我们的 application.yml 配置文件
Zuul“热身”测试的结果如下:
直连和通过 Nginx 反向代理的方式分别耗时30ms和40ms。在 Zuul 的首轮测试中,每一次请求响应耗时为388ms。正如其它博客中提到的那样,JVM 热身会有所帮助。我们又重新对 Zuul 进行一轮测试,结果如下:
Zuul在“热身”之后的性能确实有所提高,每一次请求的响应时间下降到了200ms,但是和 Nginx 反向代理平均40ms的耗时相比,还是有比较大的差距的。
将服务器升级到m4.large
正如图一所示,t2.micro ec2 仅仅是单核 1G 内存。Nginx 是 c++ 程序而 Zuul 是 Java 语言实现的。众所周知,Java 应用程序对性能的要求会更高一些。因此我们使用 m4.large 服务器(双核,8G)来进行测试。 我们再一次对 Nginx 和 Zuul 两种反向代理方式分别进行测试,结果如下:
正如以上两幅图所示,Nginx 和 Zuul 的请求响应时间分别是32ms和95ms。结果要远好于在 t2.micro 服务器进行测试时的结果。 当然,以上测试还有一个明显值得争议的问题:我们是通过 Spring Boot 应用程序来使用 Zuu l的,这自然会带来额外的性能消耗。如果我们单独对 Zuul 来进行测试,那么测试的性能结果可能还会更好。
将服务器升级到m4.2xlarge?
我们也在 m4.2xlarge 的机器(8核,32G内存)上进行了测试,Nginx 和 Zuul 的结果分别如下:
在 m4.2xlarge 的机器上,Zuul 的性能要好于 Nginx。我们想要知道 Netflix 公司是使用的哪一种 EC2 来运行 Zuul 实例的,但是却找不到对应的答案。在其它的一些博文中会有人抱怨 Zuul 的性能,然后也在询问 Netflix 公司扩展它的方式,我们觉得这次的测试结果就是答案:Zuul 的性能受限于 CPU,所以必须加 CPU。
Linkerd的测试
Linkerd 是一个云原生计算基金会的项目。它是一个 Scala 语言实现的 Service Mesh / 服务网格 应用程序,提供如服务发现等能力,但它同时也提供了反向代理的能力。我们测试了 Linkerd 的性能,结果如下图所示。Linkerd 的性能非常接近 Zuul。
Spring Cloud Gateway的测试
Spring Cloud 社区也在开发一个网关组件。虽然官方还没有正式发布这款组件,但我们认为还是需要将它和其他的可选组件一同来进行比较。因此,我们根据我们的测试环境修改了 Spring Cloud Gateway 应用程序的范例。 我们对它进行了同样的性能测试,通过 Apache Http 服务器性能测试工具,用200个并发线程进行10000次请求。结果如下: 此处输入链接的描述 如图所示,Spring Cloud Gateway 每秒处理873个请求,每个请求的响应时间是229ms。从我们测试的结果看来,Spring Cloud Gateway 并达不到 Zuul、Linkerd 和 Nginx 的水平,至少从它们当前各自 Github 上的代码是可以得到这样子的结论的。
接下来的工作
在本篇博客中,我们用Apache Http服务器性能测试工具对Zuul、Nginx、Linkerd和Spring Cloud Gateway进行了测试。以下是我们接下来的一些计划:
我们准备对 Envoy 进行评估。实际上 Envoy 不仅仅是一个 API 网关,它同时也是 Service Mesh/服务网格应用。
Undertow 也提供了反向代理的能力,也是我们接下来需要评估的。
Netflix 重新设计了 Zuul,将它设计成基于 Netty 的非阻塞应用。这个新版本叫作 "Zuul 2".我们准备在其开源版本正式发布后对其进行性能测试,然后再分享这一新 Zuul 的测试结果。
Spring Cloud Gateway 尚未开发完成,它是一个 Java 语言的基于 Netty 的非阻塞网关,因此它对于我们来说也是一个不错的选择。我们同样会对其官网版本进行性能测试。
API 网关中,一些是阻塞的,比如 Nginx 和 Zuul 1,另外一些是非阻塞的,比如 Zuul 2、Linkerd、Envoy。阻塞架构的好处在于开发简单,易于请求的追踪,但同时也会导致扩展方面的问题。非阻塞架构在开发和追踪方面会复杂一些,但是它的扩展能力和弹性伸缩能力要更加出色。因此我们加下来也会对这两种架构方案做出选择我们也会对 Gatling 进行一些测试,并在下一篇博客中分享测试结果。
我们会在接下来的每一篇博文中都对我们所取得的进展和发现进行分享,敬请期待。
这压测结果有问题。spring cloud gateway使用ab压测数据是不准的。原因是reactor-netty使用ab压测有个问题。
详见:github.com/reactor/reactor-netty/issues/21
有人提出的疑问:github.com/spring-cloud/spring-cloud-gateway/issues/124
官方的压测:github.com/spencergibb/spring-cloud-gateway-bench