CRUD工程师进阶篇——Eureka

首先说Eureka这个公司可能国内使用的不是很多。特别是现在停止更新之后,一般企业使用Zookeeper和Nacos的比较多,不过这个是万物的开源,可以学习其中的设计思想。
简单介绍下Eureka,这个东东是满足CAP中AP的,也就是说他满足可用性和分区容错性。但是不能做到一致性。
服务注册中心:Eureka,Zookeeper,Consul,Nacos
Eureka是Netfix的一个子模块,也是核心模块之一. Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。
Eureka采用了C-S的设计架构.Eureka Server作为服务注册功能的服务器,它是服务注册中心.
而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接.这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块(比如Zuul)就可以通过Eureka Server来发现务充中的其他微服务,并执行相关的操作。

 

Eureka包含两个组件:Eureka Service和Eureka Client
Eureka Server提供服务注册服务,各个节点启动后会在这里进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载复法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒),如果Eureka Server在多个心跳周期内没有接收到某 Eureka Server将会从服务注册表中把这个服务节点移除(默认90)

Eureka的简单使用:
1.首先创建一个Eureka模块,它为Eureka Service,在Pom引入jar包
<dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.1-jre</version>
        </dependency>
        <dependency>
            <groupId>com.diffplug.guava</groupId>
            <artifactId>guava-cache</artifactId>
            <version>19.0.0</version>
        </dependency>
        <!-- eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--监控-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!-- 一般通用配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
然后修改application.yml配置文件
server:
  port: 7001
eureka:
  instance:
    hostname: localhost
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
最后在启动类上加上@EnableEurekaServer
就可以完成一个Server端Eureka的实现了,通过访问7001端口就可以实时观察到目前注册进的服务了。

上述是单机模式,单机模式对于Eureka来说其实作用并不大,因为单机出现问题的时候没有替代,所有作为分布式,容灾是需要进行思考的,一般都会配置多个Eureka。集群服务就需要一个原则“相互注册,相互守望”
和上述过程一样,唯一不同的就是在yml文件中,主要把service-url配置成另外一个Eureka的地址,例如xxxxxx:7002。

其实通过对Eureka的设计进行粗略思考后,个人觉得有二个地方是可以进行深入研究的,一个是心跳机制,一个是如何实现的注册。
首先说心跳机制:
Eureka Client存在两种角色:服务提供者和服务消费者,作为服务消费者一般配合Ribbon或Feign(Feign内部使用Ribbon)使用。Eureka Client启动后,作为服务提供者立即向Server注册,默认情况下每30s续约(renew);作为服务消费者立即向Server全量更新服务注册信息,默认情况下每30s增量更新服务注册信息;Ribbon延时1s向Client获取使用的服务注册信息,默认每30s更新使用的服务注册信息,只保存状态为UP的服务。
对于client的状态一共有五种:UP,DOWN,STARTING,OUT_OF_SERVICE,UNKNOWN。

在Eureka高可用架构中,Eureka Server也可以作为Client向其他server注册,多节点相互注册组成Eureka集群,集群间相互视为peer。Eureka Client向Server注册、续约、更新状态时,接受节点更新自己的服务注册信息后,逐个同步至其他peer节点。

【注意】如果server-A向server-B节点单向注册,则server-A视server-B为peer节点,server-A接受的数据会同步给server-B,但server-B接受的数据不会同步给server-A。

缓存机制:

Eureka Server存在三个变量:(registryreadWriteCacheMapreadOnlyCacheMap)保存服务注册信息,默认情况下定时任务每30s将readWriteCacheMap同步至readOnlyCacheMap,每60s清理超过90s未续约的节点,Eureka Client每30s从readOnlyCacheMap更新服务注册信息,而UI则从registry更新服务注册信息。

 

 缓存详解:

 

 

缓存相关配置:

这边要说一个有意思的点:极限情况下服务消费者最长感知时间将无限趋近240s。

  • 0s时服务未通知Eureka Client直接下线;
  • 29s时第一次过期检查evict未超过90s;
  • 89s时第二次过期检查evict未超过90s;
  • 149s时第三次过期检查evict未续约时间超过了90s,故将该服务实例从registry和readWriteCacheMap中删除;
  • 179s时定时任务从readWriteCacheMap更新至readOnlyCacheMap;
  • 209s时Eureka Client从Eureka Server的readOnlyCacheMap更新;
  • 239s时Ribbon从Eureka Client更新。
还有一个就是触发保护机制,因为是AP,也就是说宁可不删,也不会去删正确的
所有以下几种情况:
(1) Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
(2) Eureka 仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
(3) 当网络稳定时,当前实例新的注册信息会被同步到其它节点中

 


Eureka工作流程:

1、Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息

2、Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务

3、Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常

4、当 Eureka Server 90s 内没有收到 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 将实例从注册表中删除

 

 

 

posted @ 2020-06-19 12:55  smartcat994  阅读(215)  评论(0编辑  收藏  举报