欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

谈API网关和应用网关--从技术选型谈起:API网关的性能是第一指标,一般会选择Kong、Apisix等基于OpenResty+Lua的高性能网关(得益于Ngnix基于C++的高性能无阻塞网络IO模型),应用网关一般是结合自身业务的技术栈来选择,比如SpringCloud Gateway、Zuul等。当然,这也不是绝对的,如果你对 Kong 非常熟悉,用它来做应用网关也不是不可能。 一些开源网关项目的例子: Kong Apisix 特使 Traefik SpringCloud 网关 Zuul / Zuul2 接下来,我们将重点介绍应用网关。在网格中,应用网关侧重于以下功能(与 API 网关不同) 动态路由 服务发现 服务聚合/协调 可观察性 如果您使用的是 Sping 技术栈,使用 SpringCloud Gateway 和 Zuul 可以轻松重用现有类库,如集成您的注册表,使用 Hystrix、resilience4j 完成熔断和限流功能等,快速完成一个生产级可用应用网关,如果引入新的复

最编程 2024-04-20 15:32:14
...

那么 SpringCloud Gateway 和 Zuul(指的是 Zuul 不是 Zuul2) 又有什么区别那?最大的区别就是,SpringCloud Gateway 采用的是响应式架构,而 Zuul 采用的是阻塞式架构。SpringCloud Gateway 基于 Reactor Netty 构建、Zuul基于 Servelt 构建。

阻塞式架构的问题是什么那?下面引用《RxJava 响应式编程-解决C10k问题》 一节的解释来回答,如下

阻塞式架构每一个请求都需要一个线程来处理,如果有10000个线程,那么将会面临如下情况。

  • 为了存储栈空间,消耗数个千兆字节的RAM。
  • 给垃圾收集机制带来巨大的压力,不过栈空间是不能进行垃圾收集的(大量的GC根和存活对象)。-
  • 浪费大量的CPU时间只是用于切换核心以运行各种线程(上下文切换)。

在有些场景中,经典的线程-Socket(thread-per-Socket)模型能够很好地满足要求,事实上,直到今天它在很多应用程序上都运行得非常好。但是,在达到一定级别的并发之后,线程的数量就会变得非常危险。由单个商用服务器处理1000个并发连接的情况并不罕见,在长期存活的TCP/IP连接场景中更是如此,比如带有Keep-Alive头信息的HTTP、服务器发送事件(server-sent event)和WebSocket。但是,不管线程正在进行计算还是等待数据的到达,每个线程都会占据一些内存(栈空间)。

在实现扩展性方面,有两种相互独立的方式:水平扩展和垂直扩展。为了处理更多的并发连接,我们可以部署更多的服务器,每个服务器管理负载的一个子集。这需要一个前端的负载均衡器,但是这样的方式也没有解决最初的C10k问题,即仅用一台服务器处理负载。而另一方面,垂直扩展意味着要购买更大更强的服务器。但是,由于阻塞式I/O,与未充分利用的CPU相比,需要与之不相称的内存占用。 即便大型的企业服务器能够处理数十万个并发连接(价格非常高昂),但是它却远远不能解决C10M的问题,也就是1000万个并发连接。这个数字并非巧合,数年之前,在一台典型的服务器上,一个经过精心设计的Java应用程序就达到了如此惊人的水准。

响式驱动架构又什么优势那?在阻塞式的处理模型中,每个请求对应一个线程显然无法进行扩展。响式驱动架构仅用少量线程就能管理大量客户端连接的方式。这种方式具有如下优点:

  • 减少内存消耗,减少线程上下文切换次数。
  • 更好的利用 CPU 和 CPU 缓存利用率。
  • 在单个节点上极大地提升可扩展性。

通过上述的讨论,我们很容易认为由于线程上下文的切换的减少和 CPU 缓存利用的提高,网关的性能会有一个量级的提高,但是事实真的如此吗?

Netfix 通过将核心业务逻辑放到阻塞式架构和非阻塞式架构中,在生产环境中运行了几个月后得出一个结论,系统受 CPU 限制越多,异步架构提升的效率就越少。

其实这也是符合道理的,因为响应式编程旨在通过异步的方式更好的利益 CPU,如果我们的系统本身就会处理大量的指标计算、加解密、响应压缩。从容量和 CPU 的角度来看,阻塞和非阻塞上本质上是等效的,所以每个节点的吞吐量级应该和原来差不多。

如果我们的系统请求量很大(大量的IO),但是响应很小,并且不需要加密。那么这个时候我们将同步更改为异步大约能够提升 25% 的吞吐量,同时 CPU 利用率降低 25%。根据 Netfix的生产实践,网关的工作越少我们从异步中收获的效率提升就越高。