Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul

Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul

  • 1. Why Spring Cloud?
  • 2. Spring Cloud 五大组件运行流程
  • 3. Eureka
  • 4. Ribbon
  • 5. Hystrix
  • 6. Feign
  • 7. Zuul

1. Why Spring Cloud?

  1. 灵活性——可以将解耦的服务进行组合和重新安排,以快速交付新的功能。一个正在使用的代码单元越小,更改越不复杂,测试部署代码所需的时间越短。
  2. 有弹性——解耦的服务意味着应用程序不再是单个“泥浆球”,其中一部分应用程序的降级会导致整个应用程序失败。故障可以限制在应用程序的一小部分中,并在整个应用程序遇到中断之前被控制。这也使应用程序在出现不可恢复的错误的情况下能够优雅地降级。
  3. 可伸缩性——解耦的服务可以轻松地跨多个服务器进行水平分布,从而可以适当地对功能 / 服务进行伸缩。单体应用程序中的所有逻辑是交织在一起的,即使只有一小部分应用程序是瓶颈,整个应用程序也需要扩展。小型服务的扩展是局部的,成本效益更高。
  4. 小型的、简单的、解耦的服务 = 可伸缩的、弹性的、灵活的应用程序

2. Spring Cloud 五大组件运行流程

Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul_第1张图片

3. Eureka

Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul_第2张图片

  1. 一套微服务架构的系统由很多单一职责的服务单元组成,而每个服务单元又有众多运行实例。由于各服务单元颗粒度较小、数量众多,相互之间呈现网状依赖关系,因此需要服务注册中心来统一管理微服务实例,维护各服务实例的健康状态。Spring Cloud生态体系中存在多种注册中心框架,例如Eureka、Nacos、Consul、**ZooKeeper等。
  2. Eureka Server:服务注册表维护、服务健康检查;
    1. 服务注册表维护:Eureka Server 的核心功能,用来记录各个 Service Provider 实例的状态信息。Eureka Server 提供 Provider实例清单的查询和管理API,用于查询可用的Provider实例列表,管理Provider实例的上线和下线。
    2. 服务健康检查:Eureka Server 使用一定机制定时检测已注册的Provider实例,如发现某实例长时间无法访问,就会从服务注册表中移除该实例。Eureka Server并不记录Provider的所有健康状况信息,仅仅维护了一个Provider清单。Eureka Client组件查询的Provider注册清单中,包含每一个Provider的健康状况的检查地址,通过该健康状况的地址可以查询Provider的健康状况。
  3. Eureka Client:服务注册、心跳续约、健康状况查询、服务发现、实例缓存;
    1. 服务注册:Provider 微服务实例在启动时(或者定期)将自己的信息注册到 Eureka Server 的过程。
    2. 心跳续约:Provider 实例会定时向 Eureka Server 提供 Heart beat,以表明自己还处于可用的状态。当一个Provider实例停止心跳一段时间后,注册中心会认为该服务实例不可用了,就会将该服务实例从服务注册表中剔除。如果被剔除掉的Provider实例过了一段时间后又继续向注册中心提供心跳,那么注册中心会把该Provider实例重新加入服务注册表中。
    3. 健康状况查询:Provider实例能提供健康状况查看的API,Eureka Server 或者其他的微服务Provider能够获取其健康状况。
    4. 服务发现:从注册中心查询可用Provider实例清单。
    5. 实例缓存:将从注册中心查询的Provider实例清单缓存到本地,不需要在每次使用时都去注册中心临时获取。
  4. 高可用:Eureka Server 会将自己作为服务向其他 Eureka Server 注册自己,形成一组互相注册的 Eureka Server ,以实现服务清单的互相同步,达到高可用的效果。
  5. Eureka自我保护模式与失效Provider的快速剔除:
    1. Provider服务实例注册到Eureka Server后会维护一个心跳连接,告诉Eureka Server自己还活着。Eureka Server在运行期间会统计所有Provider实例的心跳,如果心跳续约比例在一段时间间隔内(如15分钟)低于阈值(如85%),Eureka Server就会将当前所有的Provider实例的注册信息保护起来,让这些实例不会过期。
    2. 保护模式可能会导致一些问题。有时Provider服务实例会由于内存溢出、网络故障等原因不能正常运行,而处于保护模式的Eureka Server不一定会将其从服务列表中剔除出去,所以会导致客户端出现调用失败。为了使失效的Provider能够快速被剔除,可以停用Eureka Server的保护模式,然后启用客户端的健康状态检查。
    3. 自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式可以让Eureka集群更加健壮和稳定。在网络环境好、通信延迟低的场景(如开发环境)中,建议关闭自我保护模式,因为自我保护模式会导致不健康的服务得不到及时的注销。

4. Ribbon

  1. Ribbon就是一个客户端的负载均衡开源组件,是Netflix发布的开源项目。它不像服务注册中心Eureka Server、配置中心Spring Cloud Config那样独立部署,而是作为基础设施模块,几乎存在于每个Spring Cloud微服务提供者中。
  2. 从Eureka Client实例获取Provider服务列表清单,并且定期通过IPing实例判断清单中Provider服务实例的可用性。每次RPC调用到来时,在Provider服务列表清单中根据IRule策略类的Bean计算出每次RPC要访问的最终Provider。
  3. Ribbon内部有一个负载均衡器接口ILoadBalance,定义了添加Provider、获取所有的Provider列表、获取可用的Provider列表等基础的操作。该接口的核心实现类DynamicServerListLoadBalancer会通过EurekaClient(实现类为DiscoveryClient)获取Provider清单,并且通过IPing实例定期(如每10秒)向每个Provider实例发送“ping”,并且根据Provider是否有响应来判断该Provider实例是否可用。如果该Provider的可用性发生了改变,或者Provider清单中的数量和之前的不一致,就从注册中心更新或者重新拉取Provider服务实例清单。每次RPC请求到来时,由Ribbon的IRule负载均衡策略接口的某个实现类来进行负载均衡。
  4. 主要的负载均衡策略实现类
    1. 随机策略(RandomRule):RandomRule实现类从Provider服务列表清单中随机选择一个Provider服务实例,作为RPC请求的目标Provider。
    2. 线性轮询策略(RoundRobinRule):RoundRobinRule和RandomRule相似,只是每次都取下一个Provider服务器。假设一共有5台Provider服务节点,使用线性轮询策略,第1次取第1台,第2次取第2台,第3次取第3台,以此类推。
    3. 响应时间权重策略(WeightedResponseTimeRule):WeightedResponseTimeRule为每一个Provider服务维护一个权重值,它的规则简单概括为Provider服务响应时间越长,其权重就越小。在进行服务器选择时,权重值越小,被选择的机会就越少。WeightedResponseTimeRule继承了RoundRobinRule,开始时每一个Provider都没有权重值,每当RPC请求过来时,由其父类的轮询算法完成负载均衡方式。该策略类有一个默认的每30秒执行一次的权重更新定时任务,该定时任务会根据Provider实例的响应时间更新Provider权重列表。后续有RPC过来时,将根据权重值进行负载均衡。
    4. 最少连接策略(BestAvailableRule):在进行服务器选择时,该策略类遍历Provider清单,选出可用的且连接数最少的一个Provider。该策略类里面有一个LoadBalancerStats类型的成员变量,会存储所有Provider的运行状况和连接数。在进行负载均衡计算时,如果选取到的Provider为null,就会调用线性轮询策略重新选取。如果第一次RPC请求时LoadBalancerStats成员为null,就会使用线性轮询策略来获取符合要求的实例,后续的RPC在选择的时候,才能选择连接数最少的服务。每次RPC请求时,BestAvailableRule都会统计LoadBalancerStats,作为后续请求负载均衡计算的输入。
    5. 重试策略(RetryRule):该类会在一定的时限内进行Provider循环重试。RetryRule会在每次选取之后对选举的Provider进行判断,如果为null或者not alive,就会在一定的时限内(如500毫秒)不停地选取和判断。
    6. 可用过滤策略(AvailabilityFilteringRule):该类扩展了线性轮询策略,会先通过默认的线性轮询策略选取一个Provider,再去判断该Provider是否超时可用,当前连接数是否超过限制,如果都符合要求,就成功返回。简单来说,AvailabilityFilteringRule将对候选的Provider进行可用性过滤,会先过滤掉因多次访问故障而处于熔断器跳闸状态的Provider服务,还会过滤掉并发的连接数超过阈值的Provider服务,然后对剩余的服务列表进行线性轮询。
    7. 区域过滤策略(ZoneAvoidanceRule)该类扩展了线性轮询策略,除了过滤超时和连接数过多的Provider之外,还会过滤掉不符合要求的Zone区域中的所有节点。

5. Hystrix

  1. 在分布式架构中,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。针对上述问题,Spring Cloud Hystrix 实现了断路器、线程隔离等一系列服务保护功能。它也是基于 Netflix 的开源框架 Hystrix 实现的,该框架的目标在于通过控制那些访问远程系统、服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。
  2. Hystrix 具备服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并以及服务监控等强大功能。
  3. 服务降级:当服务不可用(服务正在等待、链接超时、网络延迟、服务器响应慢等),客户端一直等待时,调用fallback方法给客户端返回一个错误提示,不让客户端继续等待。
  4. 服务熔断:Spring Cloud 五大组件 简介 Eureka、Ribbon、Hystrix、Feign和Zuul_第3张图片
    1. 分布式架构中的熔断器主要用于RPC接口上,为接口安装上“保险丝”,以防止RPC接口出现拥塞时导致系统压力过大而引起的系统瘫痪。如果没有过载保护,在分布式系统中,当被调用的远程服务无法使用时,就会导致请求的资源阻塞在远程服务器上而耗尽。很多时候刚开始可能只是出现了局部小规模的故障,然而由于种种原因,故障影响范围越来越大,最终导致全局性的后果。当RPC接口流量过大或者目标Provider出现异常时,熔断器及时切断故障可以起到自我保护的作用。
    2. 熔断器具体的工作机制为:统计最近RPC调用发生错误的次数,然后根据统计值中的失败比例等信息来决定是否允许后面的RPC调用继续或者快速地失败回退。
    3. 熔断器的三种状态:
      1. 关闭(closed):熔断器关闭状态,这也是熔断器的初始状态,此状态下RPC调用正常放行。
      2. 开启(open):失败比例到一定的阈值之后,熔断器进入开启状态,此状态下RPC将会快速失败,然后执行失败回退逻辑。
      3. 半开启(half-open):在打开一定时间之后(睡眠窗口结束),熔断器进入半开启状态,小流量尝试进行RPC调用放行。如果尝试成功,熔断器就变为关闭状态,RPC调用正常;如果尝试失败,熔断器就变为开启状态,RPC调用快速失败。
  5. 线程池隔离:Docker 通过 “舱壁模式”实现进程的隔离,使得容器与容器之间不会互相影响。而 Hystrix 则使用该模式实现线程池的隔离,它会为每一个依赖服务创建一个独立的线程池,这样就算某个依赖服务出现延迟过高的情况,也只是对该依赖服务的调用产生影响,而不会拖慢其他的依赖服务。
  6. 信号量隔离:限制服务的并发请求数量。一旦达到限制,它就开始拒绝请求。
  7. 请求缓存:当系统用户不断增长时,每个微服务需要承受的并发压力也越来越大。在分布式环境下,通常压力来自于对依赖服务的调用,因为请求依赖服务的资源需要通过通信来实现,这样的依赖方式比起进程内的调用方式会引起一部分的性能损失,同时 HTTP 相比于其他高性能的通信协议在速度上没有任何优势,所以它有些类似于对数据库这样的外部资源进行读写操作,在高并发的情况下可能会成为系统的瓶颈。既然如此,我们很容易地可以联想到,类似数据访问的缓存保护是否也可以应用到依赖服务的调用上呢?
    答案显而易见,在高并发的场景之下,Hystix 中提供了请求缓存的功能,我们可以方便地开启和使用请求缓存来优化系统,达到减轻高并发时的请求线程消耗、降低请求响应时间的效果。当不同的外部请求处理逻辑调用了同一个依赖服务时,Hystrix 会根据 getCachekey 方法返回的值来区分是否是重复的请求,如果它们的 cacheKey 相同,那么该依赖服务只会在第一个请求到达时被真实地调用一次,另外一个请求则是直接从请求缓存中返回结果,所以通过开启请求缓存可以让我们实现的 Hystrix 命令具备下面几项好处:
    1. 减少重复的请求数,降低依赖服务的并发度。
    2. 在同一用户请求的上下文中,相同依赖服务的返回数据始终保持一致
    3. 请求缓存在run()和construct(执行之前生效,所以可以有效减少不必要的线程开销
  8. 请求合并:微服务架构中的依赖通常通过远程调用实现,而远程调用中最常见的问题就是通信消耗与连接数占用。在高并发的情况之下,因通信次数的增加,总的通信时间消耗将会变得不那么理想。同时,因为依赖服务的线程池资源有限,将出现排队等待与响应延迟的情况。为了优化这两个问题,Hystrix 提供了 日ystrixCo11apser 来实现请求的合并,以减少通信消耗和线程数的占用。HystrixCollapser 实现了在 HystrixCommand 之前放置一个合并处理器,将处于一个很短的时间窗(默认10毫秒)内对同一依赖服务的多个请求进行整合并以批量方式发起请求的功能(服务提供方也需要提供相应的批量实现接口)。通过 HystrixCollapser 的封装,开发者不需要关注线程合并的细节过程,只需关注批量化服务和处理。
  9. 服务监控:Hystrix Dashboard

6. Feign

  1. Spring Cloud Ribbon 和 Spring Cloud Hystrix 被作为基础工具类框架广泛地应用在各个微服务的实现中,不仅包括我们自身的业务类微服务,也包括一些基础设施类微服务(比如网关)。此外,在实践过程中,我们会发现对这两个框架的使用几乎是同时出现的。既然如此,那么是否有更高层次的封装来整合这两个基础工具以简化开发呢?Spring Cloud Feign 就是这样一个工具。它基于 Netflix Feign 实现,整合了 Spring Cloud Ribbon 与 Spring Cloud Hystrix,除了提供这两者的强大功能之外,它还提供了一种声明式的Web 服务客户端定义方式。
  2. Feign是在RestTemplate基础上封装的,使用注解的方式来声明一组与服务提供者Rest接口所对应的本地Java API接口方法。
    Feign将远程Rest接口抽象成一个声明式的FeignClient(Java API)客户端,并且负责完成FeignClient客户端和服务提供方的Rest接口绑定。
  3. Feign 使用了动态代理,使用@FeignClient调用接口的本质就是调用Feign创建的动态代理,然后根据接口上的@RequestMapping等注解,来动态构造出要请求的服务的地址并对这个地址发起请求、解析响应。
  4. Feign具备可插拔的注解支持,包括Feign注解和JAX-RS注解。同时,对于Feign自身的一些主要组件,比如编码器和解码器等,也以可插拔的方式提供,在有需求时方便扩张和替换它们。
  5. 在 Spring Cloud 中使用 Feign,可以做到使用 HTTP 请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问 HTTP 请求。
  6. Feign 整合了 Ribbon 和 Hystrix,具备负载均衡、隔离、熔断与降级功能;
  7. Feign 还提供了 HTTP 请求的模板,通过编写简单的接口和注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。Feign 会完全代理 HTTP 的请求,在使用过程中我们只需要依赖注入 Bean,然后调用对应的方法传递参数即可。

7. Zuul

  1. 微服务网关是微服务架构中不可或缺的部分:
    1. 它作为系统的统一入口,屏蔽了系统内部各个微服务的细节。
    2. 它可以与服务冶理框架结合,实现自动化的服务实例维护以及负载均衡的路由转发。
    3. 它可以实现接口权限校验与微服务业务逻辑的解耦。
    4. 通过服务网关中的过滤器,在各生命周期中去校验请求的内容,将原本在对外服务层做的校验前移,保证了微服务的无状态性,同时降低了微服务的测试难度,让服务本身更集中关注业务逻辑的处理。
  2. Zuul的功能大致有:路由、认证、限流与负载均衡。
  3. 路由:将不同REST请求转发至不同的微服务提供者,其作用类似于Nginx的反向代理。同时,也起到了统一端口的作用,将很多微服务提供者的不同端口统一到了Zuul的服务端口。
  4. 认证:网关直接暴露在公网上时,终端要调用某个服务,通常会把登录后的token(令牌)传过来,网关层对token进行有效性验证。如果token无效(或没有token),就不允许访问REST服务。可以结合Spring Security中的认证机制完成Zuul网关的安全认证。
  5. 限流:高并发场景下瞬时流量不可预估,为了保证服务对外的稳定性,限流成为每个应用必备的一道安全防火墙。如果没有这道安全防火墙,那么请求的流量超过服务的负载能力时很容易造成整个服务的瘫痪。
  6. 负载均衡:在多个微服务提供者之间按照多种策略实现负载均衡。

你可能感兴趣的:(Java,EE,软件开发实战,spring,cloud,eureka,ribbon,微服务,java)