Zuul的工作原理以及相关参数配置

Zuul的工作原理

Zuul的核心时一系列的过滤器Filter来实现的,zuul的所有功能都是基于过滤器去实现的。

Zuul Filter 的主要特点

  • Filter的类型:Filter的类型决定了此Filter在Filter链中的执行顺序。可能是路由发生前,可能路由动作发生时,可能时路由动作发生后,也可能是在路由过程发生在异常时。
  • Filter的执行顺序:统一类型的Filter可以通过filterOrder()方法来设定字定义的Filter的执行顺序。
  • Filter的执行条件:Filter运行所需要的标准或条件
  • Filter的执行效果:符合某个Filter的中条件,尝试的执行效果。

Zuul生命周期

Zuul一共有四种不同的生命周期的Filter,分别是:

  1. pre:在Zuul按照规则路由到下级服务之前执行。如果需要对请求进行预处理,比如鉴权,限流等,都应该考虑在此类Filter实现。

  2. route:这个类Filter是Zuul路由动作的执行者,是Apache HttpClient或Netflix Ribbon构建和发送原始HTTP请求的地方法,目前支持OkHttp。

  3. post:这类Filter是在源服务返回结果或者异常信息发生后执行,如果需要对返回信息做一些处理,则在此类Filter进行处理。

  4. error:在整个生命周期内如果发生异常,则会进入error Filter,可做全局异常处理。

在实际项目中,往往需要自实现以上类型的Filter来对请求链路进行处理,根据业务的需求,选取相应的生命周期的Filter来达成目的。在Filter之间,通过RequestContext类老进行通信,内部采用ThreadLocal保存你没给请求的一些信息,包括请求路由,错误信息,HttpServletRequest,HttpServletResponse,这使得一些操作时十分可靠的,它还扩张了ConcurrentHashMap,目的时为了在处理工程中保存各种形式的信息。

Zuul原生Filter

如果使用@EnableZuulProxy注解搭配Spring Boot Actuator,会看到管控的端点的信息,具体的配置如下:

添加依赖pom.xml:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
复制代码

添加配置:

management:
  endpoints:
    web:
      exposure:
        include: "*" # * 在yaml 文件属于关键字
复制代码

访问如下的地址可以看到:

名称类型次序描述
ServletDetectionFilterpre-3通过Spring Dispatcher检查请求是否通过
Servlet30WrapperFilterpre-2适配HttpServletRequest为Servlet30Wrapper对象
FormBodyWrapperFilterpre-1解析表单数据为下游请求重新编译
DebugFilterpre1Debug路由标识
PreDecorationFilterpre5处理请求上下文供后续使用,设置下游相关头信息
RibbonRoutingFilterroute10使用Ribbon,Hystrix或者嵌入式HTTP客户端发送请求
SimpleHostRoutingFilterroute100使用Apache的HttpClient发送请求
SendForwardFilterroute500使用Servlet发送请求
SendResponseFilterpost1000将代理请求的响应写入当前响应
SendErrorFiltererror0如果RquestContext.getThrowable()不为空,则转发到error,path配置的路径

由于之前的例子的启动类使用了@EnbaleZuulProxy注解后安装的Filter,如果使用了@EnaleZuulServer将缺少PreDecorationFilter,RibbonRoutingFilter,SimpleHostRoutingFilter等过滤器

以上的过滤器类有可能并不一定能够满足我们的需要,所以我们可以采取替代的方式,将其源码覆盖,也可以采取禁用策略: zuul...disable=true,比如要禁用DebugFilter,只需要在配置文件添加如下的配置: zuul.DebugFilter.pre.disable=true.

实现自定义的Filter

在Zuul中实现自定义的Filter,我们只需要集成ZuulFilter类即可,ZuulFilter是一个抽象类,我们需要实现以下的几个方法:

filterOrder():使用返回值设定Filter执行次序。

filterType():使用返回值摄动Filter类型,可以是pre,route,post,error类型。

shouldFilter():使用返回值设定该Filter是否执行,可以作为开关使用。

run():Filter里面的核心执行逻辑,业务处理在此编写。

除了是上面的方法需要重写之外,还需要把创建好的过滤器加入配置中,我们可以像下面把配置的加入内存中

@Configuration
public class ZuulFilterConfiguration {
    @Bean
    public FirstPreFilter firstPreFilter() {
        return new FirstPreFilter();
    }

    @Bean
    public SencodPreFilter sencodPreFilter() {
        return new SencodPreFilter();
    }
    @Bean
    public ThirdPreFilter thirdPreFilter(){
        return new ThirdPreFilter();
    }
    @Bean
    public PostFilter postFilter(){
        return new PostFilter();
    }
    @Bean
    public ErrorFilter errorFilter(){
        return new ErrorFilter();
    }
}
复制代码

后台打印的日志如下:

Zuul限流

限流的算法主要有两种算法,分别如下:

  1. 漏桶算法:

    漏桶算法(Leaky Bucket)是网络世界中流量整形(Traffic Shaping)或速率限制(Rate Limiting)时经常使用的一种算法,它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。

  2. 令牌算法:

令牌桶算法是网络流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。

显示限流中我们最常用的方式是定义Filter,然后加上上面的主要限流算法即可。在实际开发中我们可以使用别人现成的工具。spring-cloud-zuul-ratelimit,该框架主要用于提供Zuul的限流,该框架提供了很多细粒度的策略:

  • user:认证用户名或者匿名,针对某个用户粒度进行限流
  • origin:客户机ip,针对请求客户机ip粒度进行限流
  • url:特定的url,针对某个请求url粒度进行限流
  • serviceId:特定服务,针对某个服务id粒度进行限流

多种粒度临时变量存储方式

  • IN_MEMEORY:基于本地内存,底层是ConcurrentHashMap
  • REDIS:Redis的K/V存储
  • CONSUL:Consul的K/V存储
  • JPA:Spring Data JPA,基于数据库的存储
  • BUKE4J:一个使用JAVA编写的基于令牌算法的限流库,主要有四种模式:JCache,Hazelcast,Apache Ignite,Inifinispan。

上面主要是一些关于spring-cloud-zuul-ratelimit的一些基本的只是,现实中需要怎么使用?

pom的依赖

    <dependency>
        <groupId>com.marcosbarbero.cloud</groupId>
        <artifactId>spring-cloud-zuul-ratelimit</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>
复制代码

application.yml配置文件的配置

    zuul:
      ratelimit:
       #按力度拆分的临时变量key的前缀
        key-prefix: springcloud-book
        #启动限流开关
        enabled: true
        #key的存储类型默认是IN_MEMORY本地存储,此外还有多种形式
        repository: in_memory
        #标识代理之后,可以单独细化到服务粒度
        behind-proxy: true
        #犬奴限流策略,可单独细化到服务粒度
        default-policy:
          #在一个单位时间窗口内的请求数量
          limit: 2
          #在一个单位时间窗口内的请求时间限制
          quota: 1
          #单位时间窗口
          refresh-interval: 3
          type:
            - user
            - origin
            - url
复制代码

连续多次请求可以看到如下的结果:

Zuul的文件上传

Zuul的文件上传直接沿用了Springboot的那一套,所以配置的时候也可以想配置SpringBoot文件上传那样。

spring:
  application:
    name: zuul-server
  servlet:  #spring boot2.0之前是http
    multipart:
      enabled: true   # 使用http multipart上传处理
      max-file-size: 100MB # 设置单个文件的最大长度,默认1M,如不限制配置为-1
      max-request-size: 100MB # 设置最大的请求文件的大小,默认10M,如不限制配置为-1
      file-size-threshold: 1MB  # 当上传文件达到1MB的时候进行磁盘写入
      location: /  # 上传的临时目录


    ##### Hystrix默认超时时间为1秒,如果要上传大文件,为避免超时,稍微设大一点
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 30000
    ribbon:
      ConnectTimeout: 3000
      ReadTimeout: 30000
复制代码

Zuul的饥饿加载

Zuul内部默认使用了Ribbon来调用远程服务,所以由于Ribbon的原因,在我们部署好所有的组华南之后,第一次经历zuul的调用往往会注册中心读取服务注册表,初始化Ribbon负载信息,这是一种懒加载的策略,但是这个过程是很耗时的,尤其是服务过多的时候,为了避免这个问题,我们可以在启动的Zuul的时候就姐加载应用程序上下文信息,开启饥饿加载我们只需要配置配置文件。

zuul:
  ribbon:
    eager-load:
      enabled: true #开启饥饿加载
复制代码

重试机制

在Spring Cloud中有多种和发送Http请求的返回格式可以与Zuul结合,Ribbon,Feign或者RestTemplate,但是无论选择那种,都可以出现请求失败的情况,在复杂的网络中是无可避免的。Zuul作为uige网关中间件,在出现偶然请求失败的时候进行适当的调整是很有必要的,重试是可以有效避免一些特殊情况的引起的请求丢失的。

pom依赖:

    <!-- https://mvnrepository.com/artifact/org.springframework.retry/spring-retry -->
    <dependency>
        <groupId>org.springframework.retry</groupId>
        <artifactId>spring-retry</artifactId>
        <version>1.2.4.RELEASE</version>
    </dependency>
复制代码

配置如下:

ribbon:
  #重试机制配置
  ConnectTimeout: 3000
  ReadTimeout: 60000
  MaxAutoRetries: 1 #对第一次请求的服务的重试次数
  MaxAutoRetriesNextServer: 1 #要重试的下一个服务的最大数量(不包括第一个服务)
  OkToRetryOnAllOperations: true
复制代码

转载于:https://juejin.im/post/5cdea11f6fb9a07ebe748ee6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值