zuul网关实现解析

栏目: 编程工具 · 发布时间: 5年前

内容简介:zuul是spring cloud的网关组件,可以构建动态路由、服务降级、负载均衡的服务网关,通过filter链式调用进行扩展,实现统一认证、调用监控、日志管理等等功能。本文主要介绍zuul 1.x实现,现在zuul 2也已经开源,并且spring官方也推出了spring cloud gateway,后两者都支持非阻塞io,性能上有了一定提升,提升主要来自对于netty的引入,通过netty实现请求的接收、响应、及调用其他服务调用的io操作都是基于非阻塞io。 下图比较了三者高并发下的性能比较(下图的zu

介绍

zuul是spring cloud的网关组件,可以构建动态路由、服务降级、负载均衡的服务网关,通过filter链式调用进行扩展,实现统一认证、调用监控、日志管理等等功能。

本文主要介绍zuul 1.x实现,现在zuul 2也已经开源,并且spring官方也推出了spring cloud gateway,后两者都支持非阻塞io,性能上有了一定提升,提升主要来自对于netty的引入,通过netty实现请求的接收、响应、及调用其他服务调用的io操作都是基于非阻塞io。 下图比较了三者高并发下的性能比较(下图的zuul为1.x): zuul网关实现解析

实现

下面主要介绍下zuul的组件及怎么通过依赖ribbon(spring cloud的负载均衡组件)及hystrix(spring cloud的熔断降低服务)实现负载均衡、熔断降级功能。

主要组件:

  • ZuulFilter 这是zuul的核心,分为pre、route、post三种类型,分别对应服务调用之前、之中、之后的处理。
  • ZuulServlet 一个HttpServlet,执行所有ZuulFilter的入口。
  • Route 路由的一个节点,通常对应某个微服务。
  • RouteLocator 获取所有Route的接口,有SimpleRouteLocator和DiscoveryClientRouteLocator两种实现,后者继承自前者,前者通过配置文件配置获得,后者扩展了通过服务发现找到所有服务,并默认为所有服务生成path为/serviceId/**的Route。
  • ZuulController 需要路由的请求的统一处理器,继承自ServletWrappingController,把请求统一代理给ZuulServlet处理。
  • ZuulHandlerMapping 继承自spring mvc模块的AbstractUrlHandlerMapping,通过RouteLocator 获取到所有Route之后把route的fullPath和ZuulController注册到到HandlerMap中,把网关需要路由的路径统一映射到ZuulController

通过以上组件zuul实现了服务的动态路由,而负载均衡、熔断降级这是通过Zuul内置的ZuulFilter实现的,下图展示了filter如何运行: zuul网关实现解析 来看看Zuul有哪些内置的filter:

类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记请求是否通过spring DispatchServlet而来
pre -2 Servlet30WrapperFilter 包装HttpServletRequest请求为Servlet 3.0兼容请求
pre -1 FormBodyWrapperFilter 解析form请求体并重新编码包装
pre 1 DebugFilter 根据请求的调试参数标记调试标志
pre 5 PreDecorationFilter 根据请求URI获取的route设置请求上下文(设置请求的serviceId或者请求地址或者重定向地址)
route 10 RibbonRoutingFilter 使用ribbon及hystrix实现负载均衡、熔断降级的请求调用
route 100 SimpleHostRoutingFilter 根据Route的path进行请求调用
route 500 SendForwardFilter 根据Route重定向地址进行请求重定向,通常转发到当前应用
post 0 SendErrorFilter filter执行出错时输出响应
post 1000 SendResponseFilter filter执行成功输出响应

下面来看看RibbonRoutingFilter怎么实现负载均衡、熔断降级的服务调用,RibbonRoutingFilter内部使用一个RibbonCommandFactory来构建一个RibbonCommand,这是一个HystrixCommond,有三种具体实现,ribbon自己实现的RestClient,RibbonLoadBalancingHttpClient,OkHttpLoadBalancingClient,通过spring boot自动化配置根据classpath是否引入对应依赖来判断具体使用。 这三个client继承自AbstractLoadBalancingClient,而AbstractLoadBalancingClient又继承自AbstractLoadBalancerAwareClient,内部会构建一个LoadBalancerCommand,comond内部使用ILoadBalancer来做到负载均衡。 ILoadBalancer是ribbon的负载均衡器,不同的负载均衡策略有IRule来实现,来看看ribbon实现了哪些策略:

zuul网关实现解析

ribbon rule

AbstractLoadBalancerRule

负载均衡策略的抽象类,在该抽象类中定义了负载均衡器ILoadBalancer对象,可通过getReachableServers获取up的实例列表,通过getAllServers或者所有实例列表,为负载策略提供所需实例。

RandomRule

该策略实现了从服务实例清单中随机选择一个服务实例的功能。通过rand.nextInt(serverCount)函数来获取一个随机数,获取一个随机应用实例。

RoundRobinRule

该策略实现了按照线性轮询的方式依次选择每个服务实例的功能。通过一个count计数变量,线性轮询获取应用实例。

RetryRule

该策略实现了一个具备重试机制的实例选择功能。从下面的实现中我们可以看到,在其内部还定义了一个IRule对象,默认使用了RoundRobinRule实例。而在choose方法中的则实现了对内部定义的策略进行反复尝试的策略,若期间能够选择到具体的服务实例就返回,若选择不到就根据设置的尝试结束时间为阈值(maxRetryMillis参数定义的值 + choose方法开始执行的时间戳),当超过该阈值后就返回null。

WeightedResponseTimeRule

WeightedResponseTimeRule策略在初始化的时候会通过serverWeightTimer.schedule(new DynamicServerWeightTask(), 0, serverWeightTaskTimerInterval)启动一个定时任务,用来为每个服务实例计算权重,该任务默认30秒执行一次。

通过收集每个实例的平均耗时来计算权重,假设有4个实例A、B、C、D,他们的平均响应时间为:10、40、80、100,所以总响应时间是10 + 40 + 80 + 100 = 230,每个实例的权重为总响应时间与实例自身的平均响应时间的差的累积获得,所以实例A、B、C、D的权重分别为:

实例A:230 - 10 = 220

实例B:220 + (230 - 40)= 410

实例C:410 + (230 - 80)= 560

实例D:560 + (230 - 100)= 690

获得权重区间:

实例A:[0, 220]

实例B:(220, 410]

实例C:(410, 560]

实例D:(560,690)

通过0到690的一个随机数定位的在哪个区间来选择实例。

ClientConfigEnabledRoundRobinRule

内部使用RoundRobinRule进行负载均衡,扩展该类可以实现更丰富的负载策略,并以RoundRobinRule为降级策略。

BestAvailableRule

该策略继承自ClientConfigEnabledRoundRobinRule,在实现中它注入了负载均衡器的统计对象:LoadBalancerStats,同时在具体的choose算法中利用LoadBalancerStats保存的实例统计信息来选择满足要求的实例。它通过遍历负载均衡器中维护的所有服务实例,会过滤掉故障的实例,并找出并发请求数最小的一个,所以该策略的特性是选出最空闲的实例。

PredicateBasedRule

这是一个抽象策略,它也继承了ClientConfigEnabledRoundRobinRule,从其命名中可以猜出他是一个基于Predicate实现的策略,Predicate是Google Guava Collection工具对集合进行过滤的条件接口,通过Predicate实现来过滤出要选择的应用实例列表再从中随机一个实例。

AvailabilityFilteringRule

该策略继承自上面介绍的抽象策略PredicateBasedRule,通过RoundRobinRule选择一台实例后,使用AvailabilityPredicate匹配,如果符合条件则返回当前实例,匹配的条件是实例可用,并且ServerStats统计的活跃请求数少于配置的最大请求数,默认请求数统计窗口是10分钟。

ZoneAvoidanceRule

该策略也继承自上面介绍的抽象策略PredicateBasedRule,它使用了CompositePredicate来进行服务实例清单的过滤。这是一个组合过滤条件,在其构造函数中,它以ZoneAvoidancePredicate为主过滤条件,AvailabilityPredicate为次过滤条件初始化了组合过滤条件的实例,ZoneAvoidancePredicate该过滤条件需要实例具备区域属性,如果没有直接返回true,有的话判断所在区域是否可用(判断条件是故障实例比例小于配置值并且实例负载不为0),该策略为ribbon默认策略。

负载均衡使用ribbon实现,而熔断降级则由hystrix实现,上面也介绍了RibbonRoutingFilter内部是使用一个RibbonCommandFactory来构建一个RibbonCommand,是继承自HystrixCommond,即拥有了hystrix的熔断降级能力,对于hystrix,本文不做展开了,简单讲就是使用rxjava对RibbonCommand的执行进行各个执行状态的统计,通过判断统计结果来确定是否熔断降级,稍微介绍下rxjava。 RxJava 是一个响应式编程框架,采用观察者设计模式,主要组件如下:

  • Observable:发射源,英文释义“可观察的”,在观察者模式中称为“被观察者”或“可观察对象”;
  • Observer:接收源,英文释义“观察者”,没错!就是观察者模式中的“观察者”,可接收Observable、Subject发射的数据;
  • Subject:Subject是一个比较特殊的对象,既可充当发射源,也可充当接收源;
  • Subscriber:“订阅者”,也是接收源,那它跟Observer有什么区别呢?Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅,当你不再想接收数据了,可以调用unsubscribe( )方法停止接收,Observer 在 subscribe() 过程中,最终也会被转换成 Subscriber 对象,一般情况下,建议使用Subscriber作为接收源;
  • Subscription :Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件;
  • Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2…Action9等,Action1封装了含有 1 个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2),以此类推;
  • Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1…Func9;

本文是对zuul实现的简单介绍,顺便引出了ribbon,hystrix,rxjava等,这里的每个组件都可以单独使用。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

网站入侵与脚本攻防修炼

网站入侵与脚本攻防修炼

逍遥 / 2008-9 / 59.00元

《网站入侵与脚本攻防修炼》从“攻”、“防”两个角度,通过现实中的入侵实例,并结合原理性的分析,图文并茂地展现网站入侵与防御的全过程。全书共分8章,系统地介绍网站入侵的全部过程,以及相应的防御措施和方法。其中包括网站入侵的常见手法、流行网站脚本入侵手法揭密与防范、远程攻击入侵网站与防范、网站源代码安全分析与测试等。《网站入侵与脚本攻防修炼》尤其对网站脚本漏洞原理进行细致的分析,帮助网站管理员、安全人......一起来看看 《网站入侵与脚本攻防修炼》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具