SpringCloud作为Spring家族中的一员,它将现在非常流行的一些技术整合到一起,实现了微服务中诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等功能。
- Eureka:注册中心
- Zuul:服务网关
- Ribbon:负载均衡
- Hystix:熔断器
- Feign:服务调用
组件的调用的关系:
Eureka主要用于服务注册与发现。
Eureka包含两个组件:Eureka Server和Eureka Client。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址给消费者。
- 服务消费者从提供者地址中调用消费者。
提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,包括主机与端口号、服务版本号、通讯协议等。这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka服务端支持集群模式部署,首尾相连形成一个闭环即可。集群中的的不同服务注册中心通过异步模式互相复制各自的状态,这也意味着在给定的时间点每个实例关于所有服务的状态可能存在不一致的现象。
主要处理服务的注册和发现。客户端服务通过注册和参数配置的方式,嵌入在客户端应用程序的代码中。在应用程序启动时,Eureka客户端向服务注册中心注册自身提供的服务,并周期性的发送心跳来更新它的服务租约。同时,他也能从服务端查询当前注册的服务信息并把它们缓存到本地并周期行的刷新服务状态。
服务消费者在获取服务清单后,通过服务名可以获取具体提供服务的实例名和该实例的元数据信息。
因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例。
在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
Eureka Server在Eureka服务治理设计中,所有节点既是服务的提供方,也是服务的消费方,服务注册中心也不例外。Eureka Server的高可用实际上就是将自己做为服务向其他服务注册中心注册自己。这样就可以形成一组互相注册的服务注册中心,以实现服务清单的互相同步,达到高可用的效果。
-
Eureka Server的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。 可以采用两两注册的方式实现集群中节点完全对等的效果,实现最高可用性集群,任何一台注册中心故障都不会影响服务的注册与发现。
-
在注册服务之后,服务提供者会维护一个心跳用来持续汇报Eureka Server,我们称之为服务续约。 否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例。
-
但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了。因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题。当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据。 当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
不同的微服务一般有不同的网络地址,而外部的客户端可能需要调用多个服务的接口才能完成一个业务需求。比如一个电影购票的收集APP,可能回调用电影分类微服务,用户微服务,支付微服务等。如果客户端直接和微服务进行通信,会存在一下问题:
- 客户端会多次请求不同微服务,增加客户端的复杂性
- 存在跨域请求,在一定场景下处理相对复杂
- 认证复杂,每一个服务都需要独立认证
- 难以重构,随着项目的迭代,可能需要重新划分微服务,如果客户端直接和微服务通信,那么重构会难以实施
- 某些微服务可能使用了其他协议,直接访问有一定困难
上述问题,都可以借助微服务网管解决。微服务网管是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过微服务网关,架构演变成:
这样客户端只需要和网关交互,而无需直接调用特定微服务的接口,而且方便监控,易于认证,减少客户端和各个微服务之间的交互次数。
Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用。Zuul组件的核心是一系列的过滤器,这些过滤器可以完成以下功能:
-
身份认证和安全: 识别每一个资源的验证要求,并拒绝那些与要求不符的请求
-
审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生产视图。
-
动态路由:动态地将请求路由到不同后端集群
-
压力测试:逐渐增加指向集群的流量,以了解性能
-
负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求
-
静态响应处理:在边缘位置直接建立部分响应,避免转发到内部集群
-
多区域弹性:跨域AWS Region进行请求路由,旨在实现ELB使用多样化,以及让系统的边缘更贴近系统的使用者
Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它可以将面向服务的RestTemplate请求自动转换成客户端负载均衡的服务调用。Ribbon几乎存在于每一个微服务中,包括Feign(服务调用)也是基于Ribbon实现的。
负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,硬件负载均衡会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法从维护的可用服务端清单中取出一台服务端地址,然后进行转发。(用户请求到zuul,对用户来说是服务端负载均衡)
所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心(Eureka)。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性。(zuul用ribbon请求服务,对于zuul来说是客户端负载均衡)
Ribbon默认的负载均衡策略是简单的轮询。
负载均衡有好几种实现策略,常见的有:
- 随机 (Random)
- 轮询 (RoundRobin)
- 一致性哈希 (ConsistentHash)
- 哈希 (Hash)
- 加权轮询
- 加权随机
在分布式系统架构中多个系统之间通常是通过远程调用进行通信,比如 A 系统调用 B 系统服务,B 系统调用 C 系统的服务。当尾部应用 C 发生故障而系统 B 没有服务降级时候可能会导致 B,甚至系统 A 瘫痪,这种现象被称为雪崩现象。所以在系统设计时候要使用一定的降级策略,来保证当服务提供方服务不可用时候,服务调用方可以切换到降级后的策略进行执行。
Hystrix是容错管理工具c,作用是通过隔离、控制服务从而对延迟和故障提供更强大的容错能力,避免整个系统被拖垮。Hystrix提供的熔断器,当在一定时间段内服务调用方调用服务提供方的服务的次数达到设定的阈值,并且出错的次数也达到设置的出错阈值,就会进行服务降级,让服务调用方之间执行本地设置的降级策略,而不再发起远程调用。但是Hystrix提供的熔断器具有自我反馈,自我恢复的功能,Hystrix会根据调用接口的情况,让熔断器在closed,open,half-open三种状态之间自动切换。
- open状态说明打开熔断,也就是服务调用方执行本地降级策略,不进行远程调用。
- closed状态说明关闭了熔断,这时候服务调用方直接发起远程调用。
- half-open状态,则是一个中间状态,当熔断器处于这种状态时候,直接发起远程调用。
三种状态的转换:
- closed->open:正常情况下熔断器为closed状态,当访问同一个接口次数超过设定阈值并且错误比例超过设置错误阈值时候,就会打开熔断机制。
- open->half-open:当服务接口对应的熔断器状态为open状态时候,所有服务调用方调用该服务方法时候都是执行本地降级方法。这时Hystrix提供了一种测试策略,也就是设置了一个时间窗口,从熔断器状态变为open状态开始的一个时间窗口内,调用该服务接口时候都委托服务降级方法进行执行。如果时间超过了时间窗口,则熔断状态从open->half-open,这时候服务调用方调用服务接口时候,就可以发起远程调用了,如果还是失败,则重新设置熔断器状态为open状态,重新记录时间窗口开始时间。
- half-open->closed:当熔断器状态为half-open,这时候服务调用方调用服务接口时候,就可以发起远程调用而不再使用本地降级接口,如果发起远程调用成功,则重新设置熔断器状态为closed状态。
Feign是一种声明式、模块化的HTTP客户端,可以用来便捷优雅的进行HTTP API调用。在Spring Cloud中对Feign的使用非常简单,只需要在接口上加一些注解代码就可以了。Feign中集成了Ribbon、Eureka Client和Hystrix,从而让Feign的使用更加方便。


