暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Spring Cloud Zuul【源码篇】Zuul如何完成请求转发、限流熔断等

花好夜猿 2019-07-17
1274

参考资料:
Spring Cloud 官网
Zuul wiki

相关版本:zuul 1.3.1,spring boot 2.1.4 ,spring cloud Greenwich.SR1

回顾

Spring Cloud Zuul【源码篇】揭秘 Zuul 中知道了 Zuul 本质是 Servlet 和 Filter 结合体。

其中 Servlet 用来接收请求,而 ZuulFilter 则对请求进行包装以及处理,如:请求转发,客户端负载均衡,熔断等。

Zuul 过滤链执行顺序

Zuul 提供了一些默认的 ZuulFilter ,有的用来做请求封装,有的用来处理请求。
这些 ZuulFilter 各自有各自的作用,并按照顺序组成过滤链。
过滤链的排序规则

  • 规则一、根据 pre、route、 post route 进行区分。
    pre 优先级最高。
    route 优先级次之。
    post route 优先级最低。

  • 规则二、根据规则一进行类别区分后,每一个类别再根据自定义order 进行排序
    其中的 order 在每个 ZuulFilter 中进行设定,order 越小越优先。

验证 ZuulFilter 执行顺序

根据 pre、route、 post route 进行区分

查看源码 ZuulServlet#service 能够知道 ZuulFilter 根据类型 pre -> route -> post 优先级由高到低以此执行过滤操作。

Netflix 官方文档中,给定了一张图片同样证明 ZuulFilter 过滤链根据类型顺序执行

根据 order执行顺序

根据类型(pre、route、post) 分类执行之后,每一个分类有各自的执行顺序排列,排列参数:filterOrder 。数字越小,优先级越高。

Zuul 1.3.1 版本中 默认提供的 ZuulFilter

pre filters

过滤类优先级(越小越优先)
ServletDetectionFilter-3
Servlet30WrapperFilter-2
FormBodyWrapperFilter-1
DebugFilter1
PreDecorationFilter5

route filters

过滤类优先级(越小越优先)
RibbonRoutingFilter10
SimpleHostRoutingFilter100
SendForwardFilter500

post filters

过滤类优先级(越小越优先)
SendErrorFilter0
SendResponseFilter1000

Zuul 1.3.1 版本提供的 ZuulFilter 功能简介

  • 在 Zuul 中所有的 Filter 都需要继承 ZuulFilter。

  • 默认 ZuulFilter 是否启用有两个判断条件 
    1、zuul.{FilterCLass}.{FilterType}.disable :false 开启,true 关闭 2、
    ZuulFilter#shouldFilter 方法,返回 true 执行,返回 false 不执行

  • ZuulFilter 判定成功之后执行 ZuulFilter#run() 方法


pre filter

ServletDetectionFilter

ZuulFilter 执行触发条件

只要该过滤器开启,拦截所有请求进行过滤处理。

过滤执行逻辑

判定请求来源是不是 DispatcherServlet。并将判断结果作为参数存入 RequestContext中。

扩展:在 Spring MVC 中,在请求进入到 DispatcherServlet 中时,所有的标签会被打上标签:DispatcherServlet.class.getName() + “.CONTEXT”

Servlet30WrapperFilter

ZuulFilter 执行触发条件

只要该过滤器开启,拦截所有请求进行过滤处理。

过滤执行逻辑

判断请来源符合如下两种条件,将请求重新包装成 Servlet30RequestWrapper

  • 条件1、请求本身的包装为:HttpServletRequestWrapper

  • 条件2、请求是来自 DispatcherServlet 的请求。
    判定请求是否来自 DispathcerServlet ,已经在 ServletDetectionFilter 中判定并存入请求参数中,直接调用 RequestUtils#isDispatcherServletRequest 判断 ture or false

FormBodyWrapperFilter

ZuulFilter 执行触发条件

符合如下条件的请求才会被拦截

  • 请求中的 context-type 为 application/x-www-form-urlencoded

  • 请求来自 DispatcherServlet 并且 context-type 为 multipart/form-data

满足以上两个条件的一个的请求都会被拦截处理

过滤执行逻辑

处理的主线逻辑:将请求再一次封装,封装为 FormBodyRequestWrapper 并对 requestContext 进行 content-type 的赋值操作。(FormBodyRequestWrapper 继承 Servlet30RequestWrapper)。

DebugFilter

ZuulFilter 执行触发条件

触发条件有两种:

  • 全局开启调试
    zuul.debug.request = true 。默认:false。对所有请求进行拦截标记。

  • 针对请求设置特定参数,单一请求调试
    在 request 中设置 debug=true 参数,进行单请求设定。

过滤执行逻辑

DebugFilter 过滤器执行也很简单就是在 RequestContext 中设置 debugRouting 和 debugRequest 为 true。

开启调试之后,会在请求上下文 RequestContext 中打上标记,可以根据标记,在之后的过滤链,甚至业务中根据调试标记进行日志打印等其他调试操作

该过滤器可以实现在线上使用 debug 模式,打印相关日志信息。只需要在请求中将 debug=true 作为请求其中一个请求参数。

PreDecorationFilter

ZuulFilter 执行触发条件

过滤器的触发条件: RequestContext 中没有 FORWARD_TO_KEY 和 SERVICE_ID_KEY。

FORWARD_TO_KEY 和 SERVICE_ID_KEY 这两个值都是 PreDecorationFilter#run 执行的时候进行设置的。也就是说 被 PreDecorationFilter 处理过的请求不会被处理第二次

过滤执行逻辑

根据请求 requeset 获取 Route 信息,并将先关的参数信息,如服务id SERVICE_ID_KEY ,跳转链接 forwardURI 等存入 RequestContext 中。

post filters

RibbonRoutingFilter

ZuulFilter 执行触发条件

RibbonRoutingFilter 基于 Service id 的请求。请求上下文中需要有service id 该过滤器才会执行。

过滤执行逻辑

逻辑很清晰:通过前面一些过滤器的处理,其中 PreDecorationFilter 为请求调用设置基础的 service id ,请求路径等请求调用数据。
在此数据基础上 RibbonRoutingFilter 将这些参数信息封装为 Ribbon 请求参数,并以此作为参数发起 http 请求。

SimpleHostRoutingFilter

SimpleHostRoutingFilter 与 RibbonRoutingFilter 一样是完成 http 请求转发,不同的是 SimpleHostRoutingFilter 中的请求基于 URL,RibbonRoutingFilter 基于 Ribbon 或者 Eureka 维护的 Service id

扩展:通过在 SimpleHostRoutingFilter 实现新的 ZuulFilter ,实现自己维护服务列表。

ZuulFilter 执行触发条件

请求上下文中,请求参数带有指定请求主机。则执行该过滤链。

过滤执行逻辑

其中 SimpleHostRoutingFilter#forward 中执行逻辑:拼接 HttpClient 请求参数,发起 http 请求,获取响应数据。

SendForwardFilter

SendForwardFilter 处理需要转发的请求。

ZuulFilter 执行触发条件

需要本地跳转的请求,进行拦截处理。

执行逻辑

post filters

SendErrorFilter

处理异常的响应

ZuulFilter 执行触发条件

异常响应时触发。

执行逻辑

进行 Response 相关异常属性设置,包括 status_code,exception,message

SendResponseFilter

处理正常响应

ZuulFilter 执行触发条件

没有异常信息,并且携带相关响应数据。也就是请求响应成功的过滤处理。

过滤执行逻辑

拼接 Response ,响应数据。

总结

zuul 本质是 ZuulServlet + ZuulFilter 的结合体。

由 ZuulServlet 链接请求,然后由 一系列 ZuulFilter 组成过滤链,对请求进行处理。
Zuul 默认提供的过滤链功能如下图:

扩展:zuul 如何支持 Hystrix 功能

原理很简单:Hystrix 提供的请求熔断限流处理,所以 Hystrix 和请求的发起是紧密关联的。所以 Hystrix 相关功能必定和 请求调用关联。

zuul 请求调用有三种:

  • RibbonRoutingFilter ,service id 请求转发

  • SimpleHostRoutingFilter, url 请求转发

  • SendForwardFilter,forward 请求转发

其中支持 Hystrix 功能的是 RibbonRoutingFilter。

RibbonRoutingFilter 使用 service id 的请求转发,本质上是依赖于 Ribbon 功能实现客户端请求调用。

默认需要支持 hystrix 功能,zuul 需要通过 ribbon 维护服务实例,或者通过 eureka 维护服务实例。

zuul 使用 Ribbon 请求调用时,如何集成 Hystrix

根据 RibbonRoutingFilter#forward 中的

RibbonCommand command = this.ribbonCommandFactory.create(context); 

进行追踪。

追踪到最终发起请求调用的是 RibbonCommand#execute

RibbonCommand RibbonCommandFactory 工厂创建。

RibbonCommandFactory 工厂自动配置

其中 RibbonCommandFactory 有3个实现类:

  • RestClientRibbonCommandFactory

  • OkHttpRibbonCommandFactory

  • HttpClientRibbonCommandFactory

zuul 在自动配置类 ZuulProxyAutoConfiguration 中,根据相关依赖关系进行自动配置。

聚焦其中的一个自动配置 HttpClientRibbonCommandFactory

自动配置会生成 RibbonCommandFactory 工厂,并将我们定义的 FallbackProvider 作为构造参数。

知识点:自定义实现 hystrix fallback 功能,需要自定义类实现 FallbackProvider 接口。

有了 RibbonCommandFactory 工厂,之后就是从工厂中获取RibbonCommand 实例

聚焦 RibbonCommandFactory#create

以实现类 HttpClientRibbonCommandFactory 为例

创建 HttpClientRibbonCommand ,如果请求调用服务有自定义 FallbackProvider 则将其作为构造参数。

RibbonCommand#execute 发起请求

先来看看 RibbonCommand 实现类 HttpClientRibbonCommand 相关继承关系

跟从源码 能够得到 RibbonCommand#execute 最终调用 HystrixCommand#execute 方法。

到此就能知道 Zuul 如何提供 Hystrix 熔断功能。


-- END --

       长按二维码      

关注 [ WTF名字好难取 ] 公众号


往期回顾


Spring Cloud Zuul【源码篇】揭秘 Zuul


Spring Cloud Feign【源码篇】Feign 如何调用Ribbon进行客户端负载均衡


Spring Cloud Feign【源码篇】Feign Hystrix Support


Spring Cloud Feign【源码篇】Feign 如何进行服务间请求调用


Spring Cloud Hystrix【应用篇】 Hystrix Dashboard

文章转载自花好夜猿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论