springcloud-zuul详解(含java代码)

为什么要使用Zuul

  • Zuul作为路由网关组件,在微服务架构中有着非常重要的作用,主要体现在以下6个方面。
    • Zuul、 Ribbon 以及Eureka相结合,可以实现智能路由和负载均衡的功能,Zuul 能够将请求流量按某种策略分发到集群状态的多个服务实例。
    • 网关将所有服务的API接口统一聚合,并统一对外暴露。外界系统调用API接口时,都是由网关对外暴露的API接口,外界系统不需要知道微服务系统中各服务相互调用的复杂性。微服务系统也保护了其内部微服务单元的API接口,防止其被外界直接调用,导致服务的敏感信息对外暴露。
    • 网关服务可以做用户身份认证和权限认证,防止非法请求操作API接口,对服务器起到保护作用。
    • 网关可以实现监控功能,实时日志输出,对请求进行记录。
    • 记网关可以用来实现流量监控,在高流量的情况下,对服务进行降级。
    • API接口从内部服务分离出来,方便做测试。

API网关为微服务架构中的服务提供了统一的访问入口,客户端通过API网关访问相关服务。API网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能

Zuul作用

  • Zuul可以通过加载动态过滤机制,从而实现以下各项功能:
    • 验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。 对每一个resource进行身份认证
    • 审查与监控: 实时观察后端微服务的TPS、响应时间,失败数量等准确的信息
    • 动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
    • 压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
    • 负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
    • 静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
    • 多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
    • 日志 - 记录所有请求的访问日志数据,可以为日志分析和查询提供统一支持

Zuul的工作原理

  • Zuul是通过Servlet来实现的,Zuul通过自定义的ZuulServlet(类似于Spring MVC的DispatcherServlet)来对请求进行控制。

  • Zuul的核心是一系列过滤器,可以在Http请求的发起和响应返回期间执行一系列的过滤器。

    • Zuul包括以下4种过滤器:

      • PRE过滤器:它是在请求路由道具体的服务之前执行的,这种类型的过滤器可以做安全验证,例如身份验证、参数验证等。
      • ROUTING过滤器:它用于将请求路由到具体的微服务实例。在默认情况下,它使用Http Client进行网络请求。
      • POST过滤器:它是请求已被路由到微服务后执行的。一般情况下,用作收集统计信息、指标,以及将响应传送到客户端。
      • ERROR过滤器:它是在其他过滤器发生错误时执行的。
      • 自定义过滤器
    • filter特点

      • filter的类型:filter的类型,决定了它在整个filter链中的执行顺序,可能在端点路由前执行,也可能在端点路由时执行,还有可能在端点路由后执行,甚至是端点路由发生异常时执行。
      • filter的执行顺序:同一种类型的filter,可以通过filterOrder()方法设置执行顺序,一般都是根据业务场景自定义filter执行顺序。
      • filter执行条件:filter运行所需的标准,或条件。
      • filter执行效果:符合某个filter执行条件,产生执行效果。
  • zuul内部有一套完整的机制动态读取、编译和运行这些过滤器。过滤器之间不能直接相互通信,而是通过RequestContext对象来共享数据,每个请求都会创建一个RequestContext对象。

  • Zuul 过滤器具有以下关键特性。

    • Type(类型):Zuul过滤器的类型,这个类型决定了过滤器在请求的哪个阶段起作用,例如Pre、Post 阶段等。
    • Execution Order (执行顺序):规定了过滤器的执行顺序,Order的值越小,越先执行。
    • Criteria (标准): Filter 执行所需的条件。
    • Action (行动):如果符合执行条件,则执行Action (即逻辑代码)。
  • 过滤器生命周期图示
    在这里插入图片描述

  • 核心过滤器

过滤器名称过滤类型优先级过滤器作用
ServletDetectionFilterpre-3检测当前请求是通过DispatcherServlet处理运行的还是ZuulServlet运行处理的。
Servlet30WrapperFilterpre-2对原始的HttpServletRequest进行包装。
FormBodyWrapperFilterpre-1将Content-Type为application/x-www-form-urlencoded或multipart/form-data的请求包装成FormBodyRequestWrapper对象。
DebugFilterroute1根据zuul.debug.request的配置来决定是否打印debug日志。
PreDecorationFilterroute5对当前请求进行预处理以便执行后续操作。
RibbonRoutingFilterroute10通过Ribbon和Hystrix来向服务实例发起请求,并将请求结果进行返回。
SimpleHostRoutingFilterroute100只对请求上下文中有routeHost参数的进行处理,直接使用HttpClient向routeHost对应的物理地址进行转发。
SendForwardFilterroute500只对请求上下文中有forward.to参数的进行处理,进行本地跳转。
SendErrorFilterpost0当其他过滤器内部发生异常时的会由它来进行处理,产生错误响应。
SendResponseFilterpost1000利用请求上下文的响应信息来组织请求成功的响应内容。

Zuul请求的生命周期

  • 当一个客户端Request请求进入Zuul网关服务时,网关先进入“pre filter”, 进行一系列的验证、操作或者判断。

  • 然后交给“routing filter” 进行路由转发,转发到具体的服务实例进行逻辑处理、返回数据。

  • 当具体的服务处理完后,最后由“post filter”进行处理。

  • 该类型的处理器处理完之后,将Response信息返回给客户端。

  • ZuulServlet是Zuul的核心Servlet

    • ZuulServlet 的作用是初始化ZuulFilter,并编排这些ZuulFilter的执行顺序。
    • 该类中有一个service()方法,执行了过滤器执行的逻辑。如下
      • 首先执行preRoute()方法,这个方法执行的是PRE类型的过滤器的逻辑。
      • 如果执行这个方法时出错了,那么会执行error(e)和postRoute()。
      • 然后执行route()方法,该方法是执行ROUTING类型过滤器的逻辑。
      • 最后执行postRoute(),该方法执行了POST类型过滤器的逻辑。

服务初始化过程

  • Spring Cloud Netflix Zuul中初始化网关服务有两种方式:@EnableZuulServer和@EnableZuulProxy。

  • 这两种方式都可以启动网关服务,不同的主要地方是:

    • @EnableZuulProxy是@EnableZuulServer的超集,即使用@EnableZuulProxy加载的组件除了包含使用@EnableZuulServer加载的组件外,还增加了其他组件和功能;
    • @EnableZuulServer是纯净版的网关服务,不具备代理功能,只实现了简单的请求转发、响应等基本功能,需要自行添加需要的组件;
    • @EnableZuulProxy在@EnableZuulServer的基础上实现了代理功能,并可以通过服务发现来路由服务。
      在这里插入图片描述
  • @EnableZuulServer和@EnableZuulProxy的初始化过程一致,最大的区别在于加载的过滤器不同。

  • 蓝色是@EnableZuulServer加载的过滤器;红色是@EnableZuulProxy额外添加的过滤器。

Java实现zuul

  • 创建一个zuul-proxy模块
  • pom
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 在application.yml中进行配置
server:
  port: 8801
spring:
  application:
    name: zuul-proxy
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:8001/eureka/
  • 在启动类上添加@EnableZuulProxy注解来启用Zuul的API网关功能
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulProxyApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulProxyApplication.class, args);
    }

}
  • 启动eureka-server,两个user-service,feign-service和zuul-proxy服务
    在这里插入图片描述
配置路由规则
  • 我们可以通过修改application.yml中的配置来配置路由规则,这里我们将匹配userService/的请求路由到user-service服务上去,匹配feignService的请求路由到feign-service上去。
zuul:
  routes: #给服务配置路由
    user-service:
      path: /userService/**
    feign-service:
      path: /feignService/**
默认路由规则
  • Zuul和Eureka结合使用,可以实现路由的自动配置,自动配置的路由以服务名称为匹配路径,相当于如下配置:
zuul:
  routes: #给服务配置路由
    user-service:
      path: /user-service/**
    feign-service:
      path: /feign-service/**
zuul:
  ignored-services: user-service,feign-service #关闭默认路由配置
负载均衡功能
2022-09-24 10:31:58.738  INFO 11520 --- [nio-8202-exec-5] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
2022-09-24 10:32:00.356  INFO 11520 --- [nio-8202-exec-6] c.macro.cloud.controller.UserController  : 根据id获取用户信息,用户名称为:macro
配置访问前缀
zuul:
  prefix: /proxy #给网关路由添加前缀
Header过滤及重定向添加Host
  • Zuul在请求路由时,默认会过滤掉一些敏感的头信息,以下配置可以防止路由时的Cookie及Authorization的丢失:
zuul:
  sensitive-headers: Cookie,Set-Cookie,Authorization #配置过滤敏感的请求头信息,设置为空就不会过滤
  • Zuul在请求路由时,不会设置最初的host头信息,以下配置可以解决:
zuul:
  add-host-header: true #设置为true重定向是会添加host请求头
查看路由信息
  • 我们可以通过SpringBoot Actuator来查看Zuul中的路由信息。
  • pom添加
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 修改application.yaml配置文件,开启查看路由的端点:
management:
  endpoints:
    web:
      exposure:
        include: 'routes'
过滤器
  • 自定义过滤器
  • 添加PreLogFilter类继承ZuulFilter
    • 这是一个前置过滤器,用于在请求路由到目标服务前打印请求日志。
@Component
public class PreLogFilter extends ZuulFilter {
    private Logger LOGGER = LoggerFactory.getLogger(this.getClass());

    /**
     * 过滤器类型,有pre、routing、post、error四种。
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 过滤器执行顺序,数值越小优先级越高。
     */
    @Override
    public int filterOrder() {
        return 1;
    }

    /**
     * 是否进行过滤,返回true会执行过滤。
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 自定义的过滤器逻辑,当shouldFilter()返回true时会执行。
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String host = request.getRemoteHost();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        LOGGER.info("Remote host:{},method:{},uri:{}", host, method, uri);
        return null;
    }
}
2022-09-24 15:13:10.232  INFO 11040 --- [nio-8801-exec-7] com.macro.cloud.filter.PreLogFilter      : Remote host:0:0:0:0:0:0:0:1,method:GET,uri:/user-service/user/1
  • 禁用过滤器
    • 我们可以对过滤器进行禁用的配置,配置格式如下:
zuul:
  filterClassName:
    filter:
      disable: true 
  • 以下是禁用PreLogFilter的示例配置:
zuul:
  PreLogFilter:
    pre:
      disable: true 
Ribbon和Hystrix的支持
  • 由于Zuul自动集成了Ribbon和Hystrix,所以Zuul天生就有负载均衡和服务容错能力,我们可以通过Ribbon和Hystrix的配置来配置Zuul中的相应功能。
  • 可以使用Hystrix的配置来设置路由转发时HystrixCommand的执行超时时间:
hystrix:
  command: #用于控制HystrixCommand的行为
    default:
      execution:
        isolation:
          thread:
            #配置HystrixCommand执行的超时时间,执行超过该时间会进行服务降级处理
            timeoutInMilliseconds: 1000 
  • 可以使用Ribbon的配置来设置路由转发时请求连接及处理的超时时间:
ribbon: #全局配置
  ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
  ReadTimeout: 3000 #服务请求处理超时时间(毫秒)

常用配置

zuul:
  #给服务配置路由
  routes: 
    user-service:
      path: /userService/**
    feign-service:
      path: /feignService/**
  #关闭默认路由配置
  ignored-services: user-service,feign-service 
  #给网关路由添加前缀
  prefix: /proxy 
  #配置过滤敏感的请求头信息,设置为空就不会过滤
  sensitive-headers: Cookie,Set-Cookie,Authorization 
  #设置为true重定向是会添加host请求头
  add-host-header: true 
  # 关闭重试机制
  retryable: true 
  PreLogFilter:
    pre:
      #控制是否启用过滤器
      disable: false 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值