Spring Cloud 之 Zuul

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

  1. 在微服务分布式架构下,客户端(如浏览器)直接访问Provider服务提供者会存在以下问题:
    1. 客户端需要进行负载均衡,从多个Provider中挑选最合适的微服务提供者。
    2. 存在跨域请求时,服务端需要进行额外处理。
    3. 每个服务需要进行独立的用户认证。
  2. 解决以上问题的手段就是使用微服务网关。
  3. 微服务网关是微服务架构中不可或缺的部分,它统一解决Provider路由、均衡负载、权限控制等功能。
  4. 微服务网关的功能如图所示
  5. 微服务网关的实现框架有多种,Spring Cloud全家桶中比较常用的有Zuul和Spring Cloud Gateway两大框架。
  6. 虽然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 
    
  6. 再看第二种方式的路由规则配置:路由到微服务提供者。比如在上述代码中,有一条名为user-provider的路由规则,该规则将匹配/user-provider/**的所有URL请求,直接路由到名为user-provider的某个微服务提供者。
  7. 两种方式的区别如下:
    1. 第一种方式使用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 
    
  6. 单个路由规则的局部配置会覆盖全局的设置。

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的请求处理流程如下:
    1. 当外部请求到达Zuul网关时,首先会进入pre处理阶段,在这个阶段请求将被pre类型的过滤器处理,以完成再请求路由的前置过滤处理,比如请求的校验等。在完成pre类型的过滤处理之后,请求进入第二个阶段:route路由请求转发阶段。
    2. 在route路由请求转发阶段,请求将被route类型的过滤器处理,route类型的过滤器将外部请求转发到上游的服务。当服务实例的结果返回之后,route阶段完成,请求进入第三个阶段:post处理阶段。
    3. 在post处理阶段,请求将被post类型的过滤器处理,post类型的过滤器在处理的时候不仅可以获取请求信息,还能获取服务实例的返回信息,所以post阶段可以对处理结果进行一些加工或转换等。
    4. 还有一个特殊的阶段error,在该阶段请求将被error类型的过滤器处理,在上述3个阶段发生异常时才会触发,但是error过滤器也能将最终结果返回给请求客户端。
  7. Zuul的请求处理流程如图所示。在这里插入图片描述
  8. 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 的客户端负载均衡功能。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kuo-Teng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值