为什么要使用网关?
在当下流行的微服务架构中,面对多端应用时我们往往会做前后端分离:如前端分成 APP 端、网页端、小程序端等,使用 Vue 等流行的前端框架交给前端团队负责实现;后端拆分成若干微服务,分别交给不同的后端团队负责实现。
不同的微服务一般会有不同的服务地址,客户端在访问这些地址的时候,需要记录几十甚至几百个地址,客户端会请求多个不同的服务,需要维护不同的请求地址,增加开发难度。而且这样的机制会增加身份认证的难度,每个微服务需要独立认证,微服务网关就应运而生。
微服务网关 介于客户端与服务器之间的中间层,是系统对外的唯一入口:所有的外部请求都会先经过微服务网关,客户端只需要与网关交互,只知道一个网关地址即可。
网关是 SpringCloud 生态体系中的基础组件之一,它的主流实现方案有两个:
- Spring Cloud Netflix Zuul
- Spring Cloud Gateway
两者的主要作用都是一样的,都是代理和路由,本文主要聚焦于 Spring Cloud Netflix Zuul。
1. Zuul 网关简介
Zuul 是 Spring Cloud 中的微服务网关,是为微服务架构中的服务提供了统一的访问入口。 Zuul 本质上是一个Web servlet应用,为微服务架构中的服务提供了统一的访问入口,客户端通过 API 网关访问相关服务。
Zuul 网关的作用
网关在整个微服务的系统中角色是非常重要的,网关的作用非常多,比如路由、限流、降级、安全控制、服务聚合等。
- 统一入口:唯一的入口,网关起到外部和内部隔离的作用,保障了后台服务的安全性;
- 身份验证和安全性:对需要身份验证的资源进行过滤,拒绝处理不符合身份认证的请求;
- 动态路由:动态的将请求路由到不同的后端集群中;
- 负载均衡:设置每种请求的处理能力,删除那些超出限制的请求;
- 静态响应处理:提供静态的过滤器,直接响应一些请求,而不将它们转发到集群内部;
- 减少客户端与服务端的耦合:服务可以独立发展,通过网关层来做映射。
2. Zuul 架构总览
整体架构上可以分为两个部分,即 Zuul Core 和 Spring Cloud Netflix Zuul。
其中 Zuul Core 部分即 Zuul 的核心,负责网关核心流程的实现;Spring Cloud Netflix Zuul 负责包装Zuul Core,其中包括 Zuul 服务的初始化、过滤器的加载、路由过滤器的实现等。
3. Zuul 工作原理
- 容器启动时,Spring Cloud 初始化 Zuul 核心组件,如 ZuulServlet、过滤器等。
- ZuulServlet 处理外部请求:
- 初始化 RequestContext;
- ZuulRunner 发起执行 Pre 过滤器,并最终通过 FilterProcessor 执行;
- ZuulRunner 发起执行 Route 过滤器,并最终通过 FilterProcessor 执行;
- ZuulRunner 发起执行 Post 过滤器,并最终通过 FilterProcessor 执行;
- 返回 Http Response。
Zuul 初始化过程
Spring Cloud Netflix Zuul中初始化网关服务有两种方式: @EnableZuulServer 和 @EnableZuulProxy。
这两种方式都可以启动网关服务,不同的主要地方是:
- @EnableZuulProxy 是 @EnableZuulServer 的超集,即使用 @EnableZuulProxy 加载的组件除了包含使用 @EnableZuulServer 加载的组件外,还增加了其他组件和功能;
- @EnableZuulServer 是纯净版的网关服务,不具备代理功能,只实现了简单的请求转发、响应等基本功能,需要自行添加需要的组件;
- @EnableZuulProxy 在 @EnableZuulServer 的基础上实现了代理功能,并可以通过服务发现来路由服务。
如图所示,@EnableZuulServer 和 @EnableZuulProxy 的初始化过程一致,最大的区别在于加载的过滤器不同。其中蓝色是 @EnableZuulServer 加载的过滤器;红色是 @EnableZuulProxy 额外添加的过滤器。
Zuul 初始化源码分析
在程序的启动类加上 @EnableZuulProxy:
@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyConfiguration.class)
public @interface EnableZuulProxy {
}
复制代码
引用了 ZuulProxyConfiguration,跟踪 ZuulProxyConfiguration,该类注入了 DiscoveryClient、RibbonCommandFactoryConfiguration 用作负载均衡相关的。注入了一些列的 filters,比如 PreDecorationFilter、RibbonRoutingFilter、SimpleHostRoutingFilter,代码如如下:
ZuulProxyConfiguration.java
@Bean
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequest