写点什么

微服务架构:网关概念与 zuul

发布于: 2021 年 02 月 20 日
微服务架构:网关概念与zuul

一 网关

1.1 概念

网关定义:Gateway,网关又称网间连接器、协议转换器。默认网关在网络层以上实现网络互连,是最复杂的网络互连设备,仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似,不同的是互连层。网关既可以用于广域网互连,也可以用于局域网互连。

1.2 为什么需要网关

不同的微服务一般有不同的网络地址,而外部的客户端可能需要调用多个服务的接口才能完成一个业务需求。比如一个电影购票的收集 APP,可能回调用电影分类微服务,用户微服务,支付微服务等。如果客户端直接和微服务进行通信,会存在下列问题:

  • 客户端会多次请求不同微服务,增加客户端的复杂性

  • 存在跨域请求,在一定场景下处理相对复杂

  • 认证复杂,每一个服务都需要独立认证

  • 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通信,那么重构会难以实施

  • 某些微服务可能使用了其他协议,直接访问有一定困难


基于网关的架构:


二 zuul

2.1 什么是 zuul

zuul 是 netflix 开源的 API Gateway 服务器,本质上是一个 web servlet 应用。

zuul 提供动态路由、监控、弹性、安全等边缘服务的框架,相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。

2.2 zuul 架构

zuul 经历了 1.x 和 2.x 两个大版本,spring 又基于 zuul2 开发了 gateway,以下将分别进行简要的分析。

2.2.1 zuul1.x

Zuul1 的线程模型为多线程阻塞模型,设计比较简单,代码不多也比较容易读懂,它本质上就是一个同步 Servlet。架构如下图所示:


线程模型:


2.2.2 zuul2.x

1、架构及核心组件

据 Zuul 的 wiki 介绍,Zuul 2.x 包含以下的核心组件:

  • zuul-core - Zuul 2.0 的核心功能

  • zuul-sample - a sample driver application for Zuul 2.0 的示例驱动应用

zuul2 的大体架构如下图所示:


过滤器前端和后端的 Netty 事件处理器(handler)主要负责处理网络协议、Web 服务器、连接管理和代理工作。这些内部工作被抽象之后,所有主要的工作都会交给过滤器完成。入站过滤器在代理请求之前运行,可用于验证、路由或装饰请求。端点过滤器可用于返回静态响应,或将请求代理到后端服务。出站过滤器在返回响应后运行,可用于诸如压缩(gzipping)、指标或增删自定义请求头之类的内容。


Zuul 的功能几乎完全取决于每个过滤器的逻辑。这意味着它可以部署在多种上下文中,使用配置和运行的过滤器解决不同的问题。

2、线程模型

zuul2 的线程模型与 zuul1 有了很大区别:



Zuul2 的设计相对比较复杂,代码也不太容易读懂,它采用了 Netty 实现异步非阻塞编程模型,如上图所示。

一般异步模式的本质都是使用队列 Queue(或称总线 Bus),在上图中,你可以简单理解为前端有一个队列专门负责处理用户请求,后端有个队列专门负责处理后台服务调用,中间有个事件环线程 (Event Loop Thread),它同时监听前后两个队列上的事件,有事件就触发回调函数处理事件。这种模式下需要的线程比较少,基本上每个 CPU 核上只需要一个事件环处理线程,前端的连接数可以很多,连接来了只需要进队列,不需要启动线程,事件环线程由事件触发,没有多线程阻塞问题。

3、性能提升

Netflix 给出了一个比较模糊的数据,大致 Zuul2 的性能比 Zuul1 好 20% 左右,这里的性能主要指每节点每秒处理的请求数。为什么说模糊呢?因为这个数据受实际测试环境,流量场景模式等众多因素影响,你很难复现这个测试数据。即便这个 20% 的性能提升是确实的,其实这个性能提升也并不大,和异步引入的复杂性相比,这 20% 的提升是否值得是个问题。Netflix 本身在其博文 [附录 4] 和 ppt[附录 3] 中也是有点含糊其词,甚至自身都有一些疑问的。

While we did not see a significant efficiency benefit in migrating to async and non-blocking, we did achieve the goals of connection scaling.

比较明确的是,Zuul2 在连接数方面表现要好于 Zuul1,也就是说 Zuul2 能接受更多的连接数。

4、功能亮点



2.2.3 zuul1.x zuul2.x 对比及使用场景分析

1、架构对比

Zuul2 的架构,和 Zuul1 没有本质区别,两点变化:

前端用 Netty Server 代替 Servlet,目的是支持前端异步。后端用 Netty Client 代替 Http Client,目的是支持后端异步。

过滤器换了一下名字,用 Inbound Filters 代替 Pre-routing Filters,用 Endpoint Filter 代替 Routing Filter,用 Outbound Filters 代替 Post-routing Filters。

2、场景分析

1)Zuul 1(阻塞)的应用场景

  • cpu 密集型任务

  • 简单操作的需求

  • 开发简单的需求

  • 实时请求高的

2)Zuul 2(非阻塞)的应用场景

  • io 密集的任务

  • 大请求或者大文件

  • 队列的流式数据

  • 超大量的连接

3、小结

如果单独看 zuul1.x 和 zuul2.x,那么有建议在生产环境中继续使用 Zuul1,原因如下:

  • Zuul1 同步编程模型简单,门槛低,开发运维方便,容易调试定位问题。Zuul2 门槛高,调试不方便。

  • Zuul1 监控埋点容易,比如和调用链监控工具 CAT 集成,如果使用 Zuul2,CAT 不好埋点是个问题。

  • Zuul1 已经开源超过 7 年,稳定成熟,坑已经被踩平。Zuul2 开源时间相对较短,实际落地案例不多,难说有 bug 需要踩坑。

  • 大部分公司达不到 Netflix 那个量级,Netflix 是要应对每日千亿级流量,它们才挖空心思搞异步,一般公司亿级可能都不到,Zuul1 绰绰有余。

  • Zuul1 可以集成 Hystrix 熔断组件,可以部分解决后台服务慢阻塞网关线程的问题。

  • Zuul1 可以使用 Servlet 3.0 规范支持的 AsyncServlet 进行优化,可以实现前端异步,支持更多的连接数,达到和 Zuul2 一样的效果,但是不用引入太多异步复杂性。

事实上,Spring 整合的 zuul 也只有 1.x 版本,

同步异步各有利弊,同步多线程编程模型简单,但会有线程开销和阻塞问题,异步非阻塞模式线程少并发高,但是编程模型变得复杂。

架构师做技术选型需要严谨务实,具备批判性思维 (Critical Thinking),即使是对于一线大公司推出的开源产品,也要批判性看待,不可盲目追新。

建议生产环境继续使用 Zuul1,同步阻塞模式的一些不足,可以使用熔断组件 Hystrix 和 AsyncServlet 等技术进行优化。

2.2.4 SpringCloud Gateway

gateway 是因为 Zuul 2 停止维护,基于 Zuul2 的原理实现 springcloud 自己的网关 gateway。gateway 与 zuul2 的区别如下:

  • 两者均是 web 网关,处理的是 http 请求

  • gateway 对比 zuul 多依赖了 spring-webflux,在 spring 的支持下,功能更强大,内部实现了限流、负载均衡等,扩展性也更强,但同时也限制了仅适合于 Spring Cloud 套件,而 zuul 则可以扩展至其他微服务框架中,其内部没有实现限流、负载均衡等

  • gateway 很好的支持异步,而 zuul 仅支持同步,那么理论上 gateway 则更适合于提高系统吞吐量(但不一定能有更好的性能),最终性能还需要通过严密的压测来决定

  • 从框架设计的角度看,gateway 具有更好的扩展性,并且其已经发布了 2.0.0 的 RELESE 版本,稳定性也是非常好的.

  • 编码上看,zuul 更加简洁易懂,注释规范清晰,而 gateway 作为 Spring 家族的一份子,竟然几乎不注释…

总的来说,在微服务架构,如果使用了 Spring Cloud 生态的基础组件,则 Spring Cloud Gateway 相比而言更加具备优势,单从流式编程+支持异步上就足以让开发者选择它了。


发布于: 2021 年 02 月 20 日阅读数: 33
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
微服务架构:网关概念与zuul