当前位置: 首页 > news >正文

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:绑定请求体数据。

http://www.dtcms.com/a/20122.html

相关文章:

  • 2.【线性代数】——矩阵消元
  • C++:高度平衡二叉搜索树(AVLTree) [数据结构]
  • 【Cocos TypeScript 零基础 15.1】
  • 如何在Spring Boot中配置分布式配置中心
  • 2025-02-13 学习记录--C/C++-PTA 7-17 爬动的蠕虫
  • c#自动更新-源码
  • WPF的Prism框架的使用
  • 算法刷题-链表系列-两两交换链表结点、删除链表的倒数第n个元素
  • C#打印设计器
  • 72.git指南(简单)
  • SpringCloud系列教程:微服务的未来 (五)枚举处理器、JSON处理器、分页插件实现
  • DeepSeek24小时写作机器人,持续创作高质量文案
  • pnpm的使用
  • Python 字典思维导图
  • 制药行业 BI 可视化数据分析方案
  • dedecms 开放重定向漏洞(附脚本)(CVE-2024-57241)
  • Docker学习
  • dma_ddr 的编写 通过mig控制ddr3
  • MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 基础篇 part 13
  • 掌握SQL多表连接查询_轻松处理复杂数据关系
  • [0689].第04节:Kafka与第三方的集成 – Kafka集成SpringBoot
  • 《Spring实战》(第6版)第1章 Spring起步
  • 【数据结构】(9) 优先级队列(堆)
  • floodfill算法系列一>太平洋大西洋水流问题
  • 【第3章:卷积神经网络(CNN)——3.6 CNN的高级特性与优化策略】
  • 如何使用 DeepSeek 和 Dexscreener 构建免费的 AI 加密交易机器人?
  • EasyExcel 复杂填充
  • DeepSeek接入网络安全领域,AI高效驱动,重新定义网络防御边界!
  • UniApp 中制作一个横向滚动工具栏
  • MyBatis:动态SQL高级标签使用方法指南