Eureka Server触发自我保护机制后,页面会出现提示:
Eureka Server进入自我保护机制,会出现以下几种情况:
(1)Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
(2)Eureka仍然能够接受新服务的注册和查询,但是不会被同步到其它节点上(即保证当前节点依然可用)。
(3)当网络稳定后,当前实例新的注册信息会被同步到其它节点上。
Eureka自我保护机制是为了防止误杀服务而提供的一种机制。当个别客户端出现心跳失联时,则认为是客户端的问题,剔除客户端;当Eureka 捕获到大量的心跳失败时,则认为可能是网络问题,进入自我保护机制;当客户端心跳恢复时,Eureka会自动退出自我保护机制。
如果在保护期内刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一无效的服务实例,则会调用失败。对于这个问题需要服务消费者要有一些容错机制,比如重试,断路器等。
四、Eureka高可用集群
理论上来讲,服务消费者本地缓存了服务提供者的地址,即使Eureka Server宕机,也不会影响服务之间的调用,但是一旦涉及到服务的上下线,本地的缓存信息将会出现偏差,影响整个微服务的稳定性,因此搭建Eureka Server集群来提高整个架构的高可用性,是非常必要的。
从图中可以看出Eureka Server集群相互之间通过Replicate来同步数据,相互之间不区分主节点和从节点,所有的节点都是平等的。在这种架构中,节点通过彼此互相注册提高可用性,每个节点需要添加一个或多个有效的serviceURL指向其他节点。
如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点。当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时,所有的操作都会进行节点间复制,将请求复制到其它 Eureka Server 当前所知的所有节点中。
另外 Eureka Server 的同步遵循着一个非常简单的原则:只要有一条边将节点连接,就可以进行信息传播与同步。所以,如果存在多个节点,只需要将节点之间两两连接起来形成通路,那么其它注册中心都可以共享信息。每个 Eureka Server 同时也是 Eureka Client,多个 Eureka Server 之间通过 P2P 的方式完成服务注册表的同步。
Eureka Server 集群之间的状态是采用异步方式同步的,所以不保证节点间的状态一定是一致的,不过基本能保证最终状态是一致的。
五、 Eureka分区
Eureka提供了Region和Zone两个概念来进行分区:
Region:可以理解为地理上的不同区域,比如亚洲地区,中国地区,大连地区等等。没有具体大小的限制。根据项目具体的情况,可以自行合理划分Region。
Zone:可以简单理解为region内的具体机房,比如说region划分为大连,大连有两个机房,就可以再次region之下划分出zone1,zone2两个zone。
六、Eureka保证AP
Eureka Server 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka Client 在向某个 Eureka 注册时,如果发现连接失败,则会自动切换至其它节点。只要有一台 Eureka Server 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。
七、Eureka工作流程
1、Eureka Server启动成功,等待服务端注册。
在启动过程中如果配置了集群,集群之间定时通过Replicate同步注册表,每个Eureka Server都存在独立完整的服务注册表信息。
2、Eureka Client启动时根据配置的Eureka Server地址去注册中心注册服务。
3、Eureka Client会每30秒向Eureka Server发送一次心跳,证明客户端服务正常。
4、当Eureka Server90秒内没有收到Eureka Client的心跳,注册中心则认为该节点失效,会注销该实例。
5、单位时间内Eureka Server统计到大量的Eureka Client没有发送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有发送心跳的客户端。
6、当Eureka Client心跳恢复正常后,Eureka Server自动退出自我保护机制。
7、Eureka Client定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存在本地。
8、服务调用时,Eureka Client会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。
9、Eureka Client获取到目标服务器信息,发起服务调用。
10、Eureka Client程序关闭时向Eureka Server发送取消请求,Eureka Server将实例从注册表中剔除。
八、 Eureka Server数据存储
Eureka Server的数据存储分为两层:数据存储层和缓存层。
数据存储层记录注册到 Eureka Server上的服务信息,缓存层是经过包装后的数据,可以直接在 Eureka Client调用时返回。
Eureka Server的数据存储层是双层的ConcurrentHashMap,我们知道 ConcurrentHashMap 是线程安全高效的Map集合。
private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();
第一层的ConcurrentHashMap的key=spring.application.name也就是客户端实例注册的应用名;value为嵌套的ConcurrentHashMap。
第二层嵌套的ConcurrentHashMap的key=instanceId也就是服务的唯一实例id,value为Lease对象,Lease对象存储着这个实例的所有注册信息,包括IP、端口、属性等。
根据这个存储结构我们可以发现,Eureka Server 第一层都是存储着所有的服务名,以及服务名对应的实例信息,也就是说第一层都是按照服务应用名这个维度来切分存储:
应用名1:应用1实例 Map
应该名2:应用2实例 Map
...
第二层是根据实例的唯一 ID 来存储的,那么按照这个结构最终的存储数据格式为:
: 应用1实例A:实例A的注册信息
应用名1:应用1实例: 应用1实例B:实例B的注册信息
: 应用1实例C:实例C的注册信息
: ....
-----------------
: 应用2实例F:实例F的注册信息
应该名2:应用2实例: 应用2实例G:实例G的注册信息
: ...
...
数据存储层数据结构如下图所示:
当如服务的状态发生变更时,会同步 Eureka Server 中的 registry 数据信息,比如服务注册、剔除服务时。
九、 Eureka的缓存机制
Eureka Server 为了提供响应效率,提供了两层的缓存结构,将 Eureka Client 所需要的注册信息,直接存储在缓存结构中。
第一层缓存:readOnlyCacheMap,本质上是 ConcurrentHashMap,依赖定时从 readWriteCacheMap 同步数据,默认时间为 30 秒。
readOnlyCacheMap : 是一个 CurrentHashMap的只读缓存,这个主要为了供客户端获取注册信息时使用,其缓存更新,依赖于定时器的更新,通过和 readWriteCacheMap 的值做对比,如果数据不一致,则以 readWriteCacheMap 的数据为准。
第二层缓存: readWriteCacheMap ,本质上是Guava缓存。
readWriteCacheMap:readWriteCacheMap 的数据主要同步于存储层。当获取缓存时判断缓存中是否没有数据, 如果不存在此数据,则通过 CacheLoader 的 load 方法去加载,加载成功之后将数据放入缓存,同时返回数据。
readWriteCacheMap 缓存过期时间,默认为 180 秒,当服务下线、过期、注册、状态变更,都会来清除此缓存中的数据。
Eureka Client 获取全量或者增量的数据时,会先从一级缓存中获取;如果一级缓存中不存在,再从二级缓存中获取;如果二级缓存也不存在,这时候先将存储层的数据同步到缓存中,再从缓存中获取。
通过 Eureka Server 的二层缓存机制,可以非常有效地提升 Eureka Server 的响应时间,通过数据存储层和缓存层的数据切割,根据使用场景来提供不同的数据支持。
十、代码实例
1、项目架构
2、Eureka服务端application.yml
server:
port: 9000
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
instance:
prefer-ip-address: true
3、客户端启动类
package cn.itcast.product;
...
@SpringBootApplication
@EntityScan("cn.itcast.product.entity")
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
4、一些基本的controller、service、bean就不写了,使用的是spring data jpa方式查询的数据库。
5、启动服务
Eureka Server --> Eureka Providor --> Eureka Consumer
Eureka Server
6、Eureka Consumer调用服务
十一、总结
总结:绘上一张Kakfa架构思维大纲脑图(xmind)
其实关于Kafka,能问的问题实在是太多了,扒了几天,最终筛选出44问:基础篇17问、进阶篇15问、高级篇12问,个个直戳痛点,不知道如果你不着急看答案,又能答出几个呢?
若是对Kafka的知识还回忆不起来,不妨先看我手绘的知识总结脑图(xmind不能上传,文章里用的是图片版)进行整体架构的梳理
梳理了知识,刷完了面试,如若你还想进一步的深入学习解读kafka以及源码,那么接下来的这份《手写“kafka”》将会是个不错的选择。
-
Kafka入门
-
为什么选择Kafka
-
Kafka的安装、管理和配置
-
Kafka的集群
-
第一个Kafka程序
-
Kafka的生产者
-
Kafka的消费者
-
深入理解Kafka
-
可靠的数据传递
-
Spring和Kafka的整合
-
SpringBoot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
梳理了知识,刷完了面试,如若你还想进一步的深入学习解读kafka以及源码,那么接下来的这份《手写“kafka”》将会是个不错的选择。
-
Kafka入门
-
为什么选择Kafka
-
Kafka的安装、管理和配置
-
Kafka的集群
-
第一个Kafka程序
-
Kafka的生产者
-
Kafka的消费者
-
深入理解Kafka
-
可靠的数据传递
-
Spring和Kafka的整合
-
SpringBoot和Kafka的整合
-
Kafka实战之削峰填谷
-
数据管道和流式处理(了解即可)
[外链图片转存中…(img-KMS2FHjK-1629253383186)]