Spring Cloud — 深入了解Eureka、Ribbon及Feign

Eureka 负责服务注册与发现;Ribbon负责负载均衡;Feign简化了Web服务客户端调用方式。这三个组件可以协同工作,共同构建稳定、高效的微服务架构。

1 Eureka

分布式系统的CAP定理:

一致性(Consistency):同一个数据在集群中的所有节点,同一时刻都是同样的值。

可用性(Availability):集群中一部分节点故障后,集群整体还能处理客户端的请求。即每个请求都能收到一个(无论成功或失败)响应,且不会出现超时等情况。

分区容忍性(Partition tolerance):系统可用容忍消息的丢失或节点间通信的延迟。即分布式系统出现网络分区(由于网络故障导致系统中一部分节点无法与其他节点通信,从而形成孤立的分区)时,系统能否继续提供服务并保持数据一致性的能力。

在任何分布式系统中,不可能同时满足这三项,最多同时满足两项。

微服务的治理,核心是服务的注册和发现,针对同一服务,即使注册中心的不同节点保存的服务提供者信息不尽相同,也不会造成灾难性后果。对于消费者来说,能消费服务才是最重要的。即对于微服务的治理,遵循的是AP。

1.1 实现原理

图 服务提供者的服务生命周期

1.1.1 服务注册 Register

在服务提供者配置文件中将eureka.client.register-with-eureka的属性配置为true时,当服务提供者启动时,会调用Eureka所提供的服务注册相关方法,向Eureka服务器注册自己的信息。Eureka服务器会维护一个已注册的服务列表。

Eureka的AbstractInstanceRegistry类的ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry 字段存储了已注册的服务列表,

key 是服务的应用名称。value包含了服务实例的详细信息。

当服务实例状态发生变化时(比如不可用),服务提供者会向Eureka服务器更新自己的服务状态,同时会向其他Eureka服务器节点做状态同步。

1.1.2 服务续约 Renew

当将服务成功注册到Eureka服务器后,客户端会默认以30s(客户端配置属性eureka.instance.lease-renewal-interval-in-seconds)的频率向Eureka服务器发生一次心跳(即执行服务续约操作),来避免自己的注册信息被Eureka服务器剔除。

Eureka如果在90s内(客户端配置属性eureka.instance.lease-expiration-duration-in-seconds)没有收到客户端的心跳,则会将该服务实例从所维护的服务注册表中剔除,以禁止流向该实例的流量。

不过,当Eureka服务器处于自护保护模式时,不会清除服务实例信息。

1.1.3 获取服务

消费者端(fetch-registry属性配置为true)启动时会从Eureka服务器中获取注册表信息,并将其缓存在本地。并定期(默认30s)从Eureka服务器进行同步。

1.1.4 服务下线与剔除

当服务实例关闭时,会先向Eureka服务器发送服务下线请求,Eureka收到请求后,会将该服务实例信息从实例注册表中删除。

1.2 Eureka自我保护模式

图 处于自我保护模式下的Eureka服务

当Eureka处于自我保护模式时,会出现上面的红字提示,大概意思是:Eureka可能错误地报告服务实例为在线状态,而实际上它们可能并不在线。

这个问题是由于续租(Renewals)的数量低于阈值,导致服务实例没有被正确地标记为过期,从而可能影响到系统的稳定性和可用性。当Eureka每分钟收到心跳续租的数量恢复到阈值以上时,就会退出自我保护模式。

1.3 Eureka 高可用集群

Eureka服务器采用的是P2P(Peer to Peer)对等通信,是一种去中心化的结构。每个节点都是对等的。为了让Eureka服务高可用,必须让Eureka服务器之间能互相复制、同步所注册服务的实例信息。

图 Eureka集群注册模式

Eureka服务器配置文件中,register-with-eureka及fetch-registry属性都需要配置为true。eureka.client.service-url.defaultZone属性需要配置其他两个Eureka的服务器地址。

2 Bibbon

图 负载均衡方案核心部分

2.1 Ribbon 组件

Ribbon在实现负载均衡主要使用了6个组件。

2.1.1 服务器列表 ServerList

客户端负载均衡所使用的各服务实例列表,Ribbon支持下面3种方式:

  1. 静态服务器列表:通过BaseLoadBalancer的setServersList()方法进行设置。
  2. 基于配置的服务器列表:配置文件中通过<服务名称>.ribbon.listOfServers 属性进行配置。
  3. 基于服务发现的服务器列表:当在应用中同时使用Ribbon和Eureka时,默认会使用这种方式。当客户端启动时Ribbon会从Eureka服务器中获取所有注册服务的列表数据,并保持同步。

2.1.2 服务器列表过滤器 ServerListFilter

使用动态服务器列表时,过滤器会对原始服务列表使用一定的策略进行过滤。

|---------------------------------|------------------------------------------------------------------------|
| ZoneAffinityServerList Filter | 仅返回与本身所处区域一致的服务提供者实例列表。 |
| ServerListSubset Filter | 继承了ZoneAffinityServerListFilter,经过区域过滤后,仅返回一个固定大小的服务列表。 |
| ZonePreferenceServerList Filter | 通过配置或Eureka所属区域来过滤出同区域的服务实例列表。使用Spring Cloud整合Eureka和Ribbon时会默认使用该过滤器。 |

图 具体的服务器列表过滤器

2.1.3 服务实例存活探测 IPing

就像ping指令一样,用来监测一个微服务实例是否有响应。如果监测到某服务实例不再可用则会从列表中及时剔除。

2.1.4 负载均衡策略 IRule

负责选择一个最终服务实例地址作为负载均衡处理结果。Ribbon提供的选择策略有轮询、根据响应时间加权、断路由等。

2.1.5 负载均衡器 ILoadBalancer

负载均衡的具体实现。

|--------------------------------|--------------------------------|
| DynamicServerList LoadBalancer | 运行期间对服务实例动态更新和过滤。 |
| ZoneAware LoadBalancer | 基础上面的类。并增加防止跨区域访问的功能。 |
| NoOp LoadBalancer | 不执行实际的负载均衡操作。不会将请求分发到不同的服务实例上。 |

表 ILoadBalancer接口的具体实现类

2.1.6 服务调用器 RestClient

负载均衡后,Ribbon向服务提供者发起REST请求的工具。

2.2 负载均衡策略

Ribbon提供了以下几种负载均衡策略:

  1. 轮询策略,RoundRobinRule。轮询方式选择服务实例。即每次调度执行i=(count + 1) mod n,来选出第i台服务器实例。count为执行请求的计数次数。

  2. 随机选择,RandomRule。随机从可用的服务实例列表中选择一个。

  3. 带有加权的轮询策略,WeightedResponseTimeRule。对各个服务实例响应时间进行加权处理,然后再采用轮询的方式。

Ribbon会对每个服务实例的响应时间进行统计,根据记录的时间计算每个服务实例的权重,最后根据每个实例的权重进行概率选择。

4 .可用过滤策略,AvailabilityFilteringRule。先过滤出有故障或并发请求大于阈值的部分服务实例,然后再以线性轮询的方式。

5 .区域感知策略,ZoneAvoidanceRule。先使用主过滤条件(区域负载器,选择最优区域)来进行过滤,然后使用次过滤条件进行过滤。最后对满足条件的服务实例使用轮询策略。

3 Feigh

Feign 提供了一个简洁的接口来定义和调用远程服务。

3.1 参数绑定

在Spring MVC 中注解会以参数每次作为默认值,但Feign不会,必须声明。

@RequestMapping(value = "/user/info",method = RequestMethod.GET)
String info(@RequestParam String name);

例如上面的代码,在Spring MVC中能获取到name这个参数值,但在Feign中不会,必须写为 @RequestParam("name") String name。

Feign 支持Spring MVC的注解,Spring MVC中常用的注解有以下几种:

@RequestParam: 绑定单个请求参数值。

@PathVariable:绑定URI模板变量值。

@RequestHeader:绑定请求头数据。

@RequestBody:绑定请求体数据。

相关推荐
在京奋斗者2 小时前
spring boot自动装配原理
java·spring boot·spring
java1234_小锋9 小时前
Kafka中的消息是如何存储的?
分布式·kafka
老友@9 小时前
Kafka 深度解析:高性能设计、部署模式、容灾机制与 KRaft 新模式
分布式·kafka·kraft·高性能·容灾机制
余子桃9 小时前
Kafka的安装与使用(windows下python使用等)
分布式·kafka
java1234_小锋9 小时前
Kafka中的消息如何分配给不同的消费者?
分布式·kafka
小样vvv9 小时前
【Kafka】深入探讨 Kafka 如何保证一致性
分布式·kafka
半部论语9 小时前
SpringMVC 中的DispatcherServlet生命周期是否受Spring IOC 容器管理
java·后端·spring
小杨40410 小时前
springboot框架项目实践应用十三(springcloud alibaba整合sentinel)
spring boot·后端·spring cloud
ktkiko1110 小时前
用户模块——整合 Spring 缓存(Cacheable)
java·spring·缓存
m0_6640470212 小时前
基于Spring Boot+Layui构建企业级电子招投标系统源码
java·spring cloud·招投标系统源码·电子招标采购系统源码·企业电子招标采购系统源码