Spring Cloud 之 Zuul

本文涉及的产品
网络型负载均衡 NLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
传统型负载均衡 CLB,每月750个小时 15LCU
简介: Spring Cloud 之 Zuul

1. 微服务网关与用户身份识别

  1. 在微服务分布式架构下,客户端(如浏览器)直接访问Provider服务提供者会存在以下问题:
  1. 客户端需要进行负载均衡,从多个Provider中挑选最合适的微服务提供者。
  2. 存在跨域请求时,服务端需要进行额外处理。
  3. 每个服务需要进行独立的用户认证。
  1. 解决以上问题的手段就是使用微服务网关。
  2. 微服务网关是微服务架构中不可或缺的部分,它统一解决Provider路由、均衡负载、权限控制等功能。
  3. 微服务网关的功能如图所示
  4. 微服务网关的实现框架有多种,Spring Cloud全家桶中比较常用的有Zuul和Spring Cloud Gateway两大框架。
  5. 虽然Spring Cloud官方推荐自家的Spring Cloud Gateway框架,但是,由于Zuul使用非常广泛且文档更加丰富,因此推荐使用Zuul作为生产场景的微服务网关,在高并发的使用场景中则推荐使用Spring Cloud Gateway框架作为网关。


2. Zuul 简介

  1. Zuul是Netflix公司的开源网关产品,可以和Eureka、Ribbon、Hystrix等组件配合使用。
  2. Zuul的规则引擎和过滤器基本上可以用任何JVM语言编写,内置支持Java和Groovy。
  3. 在Spring Cloud框架中,Zuul的角色是网关,负责接收所有的REST请求(如网页端、App端等),然后进行内部转发,是微服务提供者集群的流量入口。
  4. 将Zuul称为内部网关,以便和Nginx外部网关相区分。
  5. Spring Cloud对Zuul进行了整合与增强。
  6. Zuul作为网关层,自身也是一个微服务,跟其他服务提供者一样都注册在Eureka Server上,可以相互发现。
  7. Zuul能感知到哪些Provider实例在线,同时通过配置路由规则可以将REST请求自动转发到指定的后端微服务提供者。
  8. Zuul的功能大致有:


  1. 路由:将不同REST请求转发至不同的微服务提供者,其作用类似于Nginx的反向代理。同时,也起到了统一端口的作用,将很多微服务提供者的不同端口统一到了Zuul的服务端口。
  2. 认证:网关直接暴露在公网上时,终端要调用某个服务,通常会把登录后的token(令牌)传过来,网关层对token进行有效性验证。如果token无效(或没有token),就不允许访问REST服务。可以结合Spring Security中的认证机制完成Zuul网关的安全认证。
  3. 限流:高并发场景下瞬时流量不可预估,为了保证服务对外的稳定性,限流成为每个应用必备的一道安全防火墙。如果没有这道安全防火墙,那么请求的流量超过服务的负载能力时很容易造成整个服务的瘫痪。
  4. 负载均衡:在多个微服务提供者之间按照多种策略实现负载均衡。


3. 创建Zuul网关服务

  1. 添加依赖
<dependency> 
  <groupId>org.springframework.cloud</groupId> 
  <artifactId>spring-cloud-starter-netflix-zuul</artifactId> 
</dependency> 

2.在启动类中添加注解@EnableZuulProxy,声明这是一个网关服务提供者

package com.crazymaker.springcloud.cloud.center.zuul; 
... 
@EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class}) 
@SpringBootApplication(scanBasePackages = {"com.crazymaker.springcloud.cloud.center.zuul", "com.crazymaker.springcloud.standard", "com.crazymaker.springcloud.user.info.contract" }) 
@EnableScheduling 
@EnableHystrix 
@EnableDiscoveryClient 
//开启网关服务 
@EnableZuulProxy 
@EnableCircuitBreaker 
public class ZuulServerApplication { 
  public static void main(String[] args) { 
      SpringApplication.run(ZuulServerApplication.class, args); 
  } 
} 


3.1. Zuul路由配置规则

  1. 作为反向代理,Zuul需要通过路由规则将REST请求转发到上游的微服务Provider。
  2. crazy-springcloud脚手架中Zuul网关的路由规则配置示例:
#服务网关配置 
zuul: 
ribbonIsolationStrategy: THREAD 
host: 
  connect-timeout-millis: 600000 
  socket-timeout-millis: 600000 
#路由规则 
routes: 
  seckill-provider: 
    path: /seckill-provider/** 
    serviceId: seckill-provider 
    strip-prefix: false 
   message-provider: 
    path: /message-provider/** 
    serviceId: message-provider 
    strip-prefix: false 
   user-provider: 
    path: /user-provider/** 
    serviceId: user-provider 
    strip-prefix: false 
   backend-provider: 
    path: /backend-provider/** 
    serviceId: backend-provider 
    strip-prefix: false 
   generate-provider: 
    path: /generate-provider/** 
    serviceId: generate-provider 
    strip-prefix: false 
    sensitiveHeaders: Cookie,Set-Cookie,token,backend,Authorization       
   demo-provider: 
    path: /demo-provider/** 
    serviceId: demo-provider 
    strip-prefix: false 
   urlDemo: 
    path: /blog/** 
    url: https://www.cnblogs.com 
    sensitiveHeaders: Cookie,Set-Cookie,token,backend,Authorization 

3.以上示例中,有两种方式的路由规则配置:(1)路由到直接URL;(2)路由到微服务提供者。

4.先看第一种方式的路由规则配置:路由到直接URL。在上述示例中,有一条名为urlDemo的路由规则,该规则匹配到格式为/blog/**的所有URL请求,直接转发到https://www.cnblogs.com的地址上;

5.比如,通过网关访问如下URL:

http://127.0.0.1:7799/blog/crazymakercircle/p/9904544.html

此URL满足/blog/**的匹配规则,将被Zuul直接转发到上游的URL地址:

https://www.cnblogs.com/crazymakercircle/p/9904544.html
  1. 再看第二种方式的路由规则配置:路由到微服务提供者。比如在上述代码中,有一条名为user-provider的路由规则,该规则将匹配/user-provider/**的所有URL请求,直接路由到名为user-provider的某个微服务提供者。
  2. 两种方式的区别如下:
  3. 第一种方式使用url属性来指定直接的上游URL的前缀;第二种方式使用serviceId属性来指定上游服务提供者的名称。

2.第二种方式需要结合Eureka Client客户端来实现动态的路由转发功能,启动类需要加上注解@EnableDiscoveryClient,只能用于Spring Cloud架构中。其实该注解也可以不加,因为网关注解@EnableZuulProxy已经默认进行了导入。

3.2. 过滤敏感请求头部

  1. 在同一个系统中,在不同Provider之间共享请求头是可行的,但是,如果Zuul需要将请求转发到外部,可能不希望敏感的请求头泄露到外部的其他服务器。
  2. 防止请求头泄露的方式之一是,在Zuul的路由配置中指定要忽略的请求头列表,并且多个敏感头部之间可以用逗号隔开。下面是一个简单的实例:
spring: 
application: 
  name: cloud-zuul 
zuul: 
sensitiveHeaders: Cookie,Set-Cookie,token,backend,Authorization 

3.Cookie经常用于在流量中缓存用户的会话、用户凭证等信息,对于外部系统而言是需要保密的,所以应该设置为敏感标题,不应该带往系统外部。

4.默认情况下,Zuul转发请求时会把header清空,如果在微服务集群内部转发请求,上游Provider就会收不到任何头部。

5.也可对单个路由规则进行局部配置,比如crazy-springcloud脚手架中专门对外部的转发规则urlDemo进行了请求头的屏蔽,它的配置如下:

#服务网关路由规则 
zuul: 
routes: 
  urlDemo: 
    path: /blog/** 
    url: https://www.cnblogs.com 
    sensitiveHeaders: Cookie,Set-Cookie,token,backend,Authorization 


  1. 单个路由规则的局部配置会覆盖全局的设置。

3.3. 路径前缀的处理

  1. 如果不进行任何配置,默认情况下Zuul会去掉路由的路径前缀。
  2. 如果上游的微服务提供者没有配置路径前缀,Zuul的这种默认处理和转发就不会有问题。
  3. 如果上游提供者配置了统一的路径前缀,而前缀被去掉,上游服务提供者就会报出404的错误,也就是找不到URL对应的资源。
  4. 在Zuul进行路由处理时,如何保留请求URL中的路径前缀呢?可以设置配置项stripPrefix的值为false,确保路径前缀不会截取掉。stripPrefix的值默认为true。

4. Zuul过滤器

  1. Spring Cloud Zuul除了可以实现请求的路由功能外,还有一个重要的功能就是过滤器。
  2. Zuul可以通过定义过滤器来实现请求的拦截和过滤,而它本身的大部分功能也是通过过滤器实现的。


4.1. Zuul网关的过滤器类型

  1. pre类型的过滤器:此类型为请求路由之前调用的过滤器,可利用此类过滤器来实现身份验证、记录调试信息等。
  2. route类型的过滤器:此类型为发送请求到上游服务的过滤器,比如使用Apache HttpClient或Netflix Ribbon请求上游服务。
  3. post类型的过滤器:此类型为上游服务返回之后调用的过滤器,可用来为响应添加HTTP响应头、收集统计信息和指标、将响应回复给客户端。
  4. error类型的过滤器:此类型为在其他阶段发生错误时执行的过滤器。
  5. 除了默认的过滤器类型外,Zuul还允许我们创建自定义的过滤器类型,例如可以定制一种echo类型的过滤器,直接在Zuul中生成响应,而不将请求转发到上游的服务。
  6. Zuul的请求处理流程如下:
  7. 当外部请求到达Zuul网关时,首先会进入pre处理阶段,在这个阶段请求将被pre类型的过滤器处理,以完成再请求路由的前置过滤处理,比如请求的校验等。在完成pre类型的过滤处理之后,请求进入第二个阶段:route路由请求转发阶段。
  8. 在route路由请求转发阶段,请求将被route类型的过滤器处理,route类型的过滤器将外部请求转发到上游的服务。当服务实例的结果返回之后,route阶段完成,请求进入第三个阶段:post处理阶段。
  9. 在post处理阶段,请求将被post类型的过滤器处理,post类型的过滤器在处理的时候不仅可以获取请求信息,还能获取服务实例的返回信息,所以post阶段可以对处理结果进行一些加工或转换等。
  10. 还有一个特殊的阶段error,在该阶段请求将被error类型的过滤器处理,在上述3个阶段发生异常时才会触发,但是error过滤器也能将最终结果返回给请求客户端。

7.Zuul的请求处理流程如图所示。

  1. Zuul提供了一个动态读取、编译和运行过滤器的框架。过滤器不直接相互通信,而是通过RequestContext共享状态,RequestContext(请求上下文)实例对每个请求都是唯一的。



5. Hystrix和Ribbon支持

  1. spring-cloud-starter-zuul 依赖本身就包含了spring-cloud-starter-hystrix 和 spring-cloud-starter-ribbon 模块的依赖,所以Zuul天生就拥有线程隔离和断路器的自我保护功能,以及对服务调用的客户端负载均衡功能。
  2. 但是需要注意,当使用path与url的映射关系来配置路由规则的时候,对于路由转发的请求不会采用 HystrixCommand 来包装,所以这类路由请求没有线程隔离和断路器的保护,并且也不会有负载均衡的能力。因此,我们在使用 Zuul 的时候尽量使用 path 和serviceId 的组合来进行配置,这样不仅可以保证 API 网关的健壮和稳定,也能用到 Ribbon 的客户端负载均衡功能。
相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
5月前
|
监控 负载均衡 Java
深入理解Spring Cloud中的服务网关
深入理解Spring Cloud中的服务网关
|
16天前
|
消息中间件 监控 Java
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
31 6
|
16天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
36 5
|
16天前
|
缓存 监控 Java
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
27 5
|
5月前
|
设计模式 监控 Java
解析Spring Cloud中的断路器模式原理
解析Spring Cloud中的断路器模式原理
|
3月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
154 5
|
5月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
15037 32
|
5月前
|
负载均衡 Java Spring
Spring cloud gateway 如何在路由时进行负载均衡
Spring cloud gateway 如何在路由时进行负载均衡
562 15
|
5月前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
126 3