SpringCloud之Eureka原理分析与实战(注册与发现)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

1、从本质理解服务治理思想

2、为什么选择Spring Cloud服务治理组件

3、Spring Cloud Eureka服务发现

3.1 Eureka的优势

3.2 Eureka架构组成

3.3 搭建Eureka Server 实战

3.3.1 添加依赖

3.3.2 开启服务注册

3.3.3 添加YML配置

3.3.4 访问服务

3.4 搭建Eureka Client实战

3.4.1 添加依赖

3.4.2 开启服务注册

3.4.3 添加YML配置

3.4.4 访问服务

4、什么是自我保护模式

4.1 自我保护原理

4.2 自我保护触发条件

4.2.1 触发条件

4.2.2 Renews threshold

4.2.3 Renews

4.2.4 如何解决


1、从本质理解服务治理思想

我们经常听到的一个词就是“服务治理”。很多文章似乎竭力用技术层面的架构在解释什么是服务治理。很少有人能用通俗易懂的语言来阐述。今天老王试着从通俗易懂角度给大家解释一下。

那怎么理解“服务治理”呢

首先要理解什么是“服务”。服务源于应用而又高于应用。什么意思呢

从字面意思理解服务就是一个一个应用。但与“治理”建立联系后那就上升到了服务与服务之间的通讯交互监控等管理。所以服务治理更多的是从服务和服务之间的可能存在什么问题而服务治理就是需要去解决这个问题。如果是以前传统单体应用也就不存这个问题。而当下分布式系统盛行所以我们需要各种组件来保障分布式系统之间能保持高稳定、高可用性等。

基于这样的目的也就有了像Eureka、Consul和Zookeeper这类中间件的出现。

2、为什么选择Spring Cloud服务治理组件

在理解了什么是“服务治理”后接下来我们进入今天要讲解的主角Eureka。

首先我们要知道为什么选择Spring Cloud的服务治理框架。

前面我们提到当下基本90%的业务系统属于分布式部署而分布式系统之间大多都采用RPCRemote Procedure Call远程过程调用的方式通信那在PRC调用过程中,如何解决多样化的服务注册中来监控服务是否可用不可用情况下该怎么办中断业务还是通过其他方式快速恢复业务等等。 那这些问题就需要通过“服务注册与发现”组件来解决。

那在服务注册组件中我们之所以选择Spring Cloud主要是由于Spring Cloud为服务治理做了一层抽象接口所以在Spring Cloud应用中可以支持多种不同的服务治理框架。

比如Netflix Eureka、Consul、Zookeeper。在Spring Cloud服务治理抽象层的作用下我们可以无缝地切换服务治理实现并且不影响任何其他的服务注册、服务发现、服务调用等逻辑。

3、Spring Cloud Eureka服务发现

Spring Cloud Eureka是Spring Cloud Netflix项目下的服务治理模块。而Spring Cloud Netflix项目是Spring Cloud的子项目之一主要内容是对Netflix公司一系列开源产品的包装它为Spring Boot应用提供了自配置的Netflix OSS整合。通过一些简单的注解开发者就可以快速的在应用中配置一下常用模块并构建庞大的分布式系统。它主要提供的模块包括服务发现Eureka断路器Hystrix智能路由Zuul客户端负载均衡Ribbon等。

那在众多服务发现组件中我们为什么选择Eureka呢

3.1 Eureka的优势

1提供完整的服务注册和服务发现实现机制

首先Eureka提供了完整的服务注册和服务发现的实现机制并且也经受住了Netflix自己的生产环境考验稳定性方面相对使用起来会比较放心。

2与SpirngCloud无缝集成

我们的项目本身就使用了Spring Cloud和Spring Boot同时Spring Cloud还有一套非常完善的开源代码来整合Eureka所以使用起来非常方便。另外Eureka还支持在我们应用自身的容器中启动也就是说我们的应用启动完之后既充当了Eureka的角色同时也是服务的提供者。这样就极大的提高了服务的可用性。

3CAP采用AP而非CP

这个是经典的CAP理论。

我们知道CAP原则指的是在一个分布式系统中一致性Consistency、可用性Availability、分区容错性Partition tolerance但是CAP 原则指示3个要素最多只能同时实现两点不可能三者兼顾由于网络硬件肯定会出现延迟丢包等问题但是在分布式系统中我们必须保证部分网络通信问题不会导致整个服务器集群瘫痪另外即使分成了多个区当网络故障消除的时候我们依然可以保证数据一致性所以我们必须保证分区容错性。

而EurekaEureka是Netflix开发的服务发现框架本身是一个基于REST的服务主要用于定位运行在AWS域中的中间层服务以达到负载均衡和中间层服务故障转移的目的。在部署AWS的背景下其设计者认为在云端特别是大规模部署情况下面失败是不可以避免的可能是因为Eureka自身部署失败或者网络分区等情况导致服务不可用这些问题是不可以避免的要解决这个问题就需要Eureka在网络分区的时候还能够正常提供服务因此Eureka选择满足Availability这个特性。

在生产实践中服务注册及发现中保留可用以及过期的数据总比丢失可用的数据好。因此

eureka选择了A也就必须放弃C也就是说在eureka中采用最终一致性的方式来保证数据的一致性问题因此实例的注册信息在集群的所有节点之间的数据都不是强一性的需要客户端能支持负载均衡算法及失败重试等机制。这也是Eureka被病垢的主要原因但优点多余缺点可以通过重试等补偿机制来完善。

综上我们可以看到每个注册中心组件都有其优缺点。我们在实际开发过程当中需要结合实际情况来做技术选型。

4组件开源

代码是开源的而且也是由Java语言开发。所以非常便于我们了解它的实现原理和排查问题。需要的话还可以在上面进行二次开发。

3.2 Eureka架构组成

Eureka主要包含Eureka Server和 Eureka Client两部分。其架构设计图如下

其中Eureka Server提供服务注册服务各个节点启动后会在Eureka Server中进行注册这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息服务节点的信息可以在界面中直观的看到。

而Eureka Client是一个java客户端用于简化与Eureka Server的交互客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。

在应用启动后将会向Eureka Server发送心跳,默认周期为30秒如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

Eureka Server之间通过复制的方式完成数据的同步Eureka还提供了客户端缓存机制即使所有的Eureka Server都挂掉客户端依然可以利用缓存中的信息消费其他服务的API。综上Eureka通过心跳检查、客户端缓存等机制确保了系统的高可用性、灵活性和可伸缩性。

Eureka Server 处理过程

Eureka Server 也可以运行多个实例来构建集群解决单点问题但不同于 ZooKeeper 的选举 leader 的过程Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构无 master/slave 之分每一个 Peer 都是对等的。

在这种架构风格中节点通过彼此互相注册来提高可用性每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。

在集群环境中如果某台 Eureka Server 宕机Eureka Client 的请求会自动切换到新的 Eureka Server 节点上当宕机的服务器重新恢复后Eureka 会再次将其纳入到服务器集群管理之中。当节点开始接受客户端请求时所有的操作都会在节点间进行复制replicate To Peer操作将请求复制到该 Eureka Server 当前所知的其它所有节点中。

当一个新的 Eureka Server 节点启动后会首先尝试从邻近节点获取所有注册列表信息并完成初始化。Eureka Server 通过 getEurekaServiceUrls() 方法获取所有的节点并且会通过心跳契约的方式定期更新。

默认情况下如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳默认周期为30秒Eureka Server 将会注销该实例默认为90秒 eureka.instance.lease-expiration-duration-in-seconds 进行自定义配置。

当 Eureka Server 节点在短时间内丢失过多的心跳时那么这个节点就会进入自我保护模式。

Eureka的集群中只要有一台Eureka还在就能保证注册服务可用保证可用性只不过查到的信息可能不是最新的不保证强一致性。除此之外Eureka还有一种自我保护机制如果在15分钟内超过85%的节点都没有正常的心跳那么Eureka就认为客户端与注册中心出现了网络故障此时会出现以下几种情况

Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务

Eureka仍然能够接受新服务注册和查询请求但是不会被同步到其它节点上即保证当前节点依然可用

当网络稳定时当前实例新注册的信息会被同步到其它节点中

因此Eureka可以很好的应对因网络故障导致部分节点失去联系的情况而不会像zookeeper那样使得整个注册服务瘫痪。

3.3 搭建Eureka Server 实战

说明实战部分可以接着我们昨天讲的例子来继续编写。我这里为了在代码结构上能更加清晰将Eureka Server和Eureka Client拆分成了两个独立的module。

如下图

在前一篇文章中我们其实已经讲解了Eureka Server的搭建。这里就不再赘述。直接上配置和代码基于springcloud-eureka-server这个module。

3.3.1 添加依赖

在项目 springcloud-eureka-server pom.xml文件中引入需要的依赖内容

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-eureka-server</artifactId>

</dependency>

3.3.2 开启服务注册

通过 @EnableEurekaServer 注解启动一个服务注册中心提供给其他应用进行对话,这个注解需要在springboot工程的启动SpringCloudEurekaServerApp类上加。代码如下


package com.xintu.springcloud;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;



@SpringBootApplication

@EnableEurekaServer //表示可以将项目作为SpringCloud中的注册中心。用于激活Eureka服务器相关配置EurekaServerAutoConfiguration的注释。

public class SpringCloudEurekaServerApp {



public static void main(String[] args) {

SpringApplication.run(SpringCloudEurekaServerApp.class, args);

}



}

3.3.3 添加YML配置

在默认设置下该服务注册中心也会将自己作为客户端来尝试注册它自己所以我们需要禁用它的客户端注册行为只需要在application.yml配置文件中增加如下信息


#指定应用名称

spring:

  application:

    name: eureka-server



# 服务注册中心 (单节点)

server:

  port: 8700

eureka:

  instance:

    hostname: localhost

  client:

    fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false

    register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.

    service-url:

      # 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址.默认是http://localhost:8761/eureka/;多个地址可使用','风格.

      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3.3.4 访问服务

启动工程后访问http://localhost:8700/。可以看到下面的页面其中还没有发现任何服务。

至此Eureka Serve实战案例搭建完成。

3.4 搭建Eureka Client实战

Eureka Client也称为服务提供方将自身服务注册到 Eureka 注册中心从而使服务消费方能够找到。

3.4.1 添加依赖

在项目 spring-cloud-eureka-provider pom.xml中引入需要的依赖内容

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>

3.4.2 开启服务注册

在应用启动SpringCloudEurekaClientApp中通过加上 @EnableEurekaClient但只有Eureka 可用你也可以使用@EnableDiscoveryClient。需要配置才能找到Eureka注册中心服务器。


package com.xintu.springcloud;



import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.cloud.client.discovery.EnableDiscoveryClient;



@SpringBootApplication

@EnableDiscoveryClient//代表自己是一个服务提供方

public class SpringCloudEurekaClientApp {



public static void main(String[] args) {

SpringApplication.run(SpringCloudEurekaClientApp.class, args);

}



}

3.4.3 添加YML配置

需要配置才能找到Eureka服务器。配置如下


#指定应用名称

spring:

  application:

    name: eureka-client



server:

  port: 8701 # 服务提供方



# 指定当前eureka客户端的注册地址,

eureka:

  instance:

    hostname: localhost

  client:

    service-url:

      defaultZone: http://${eureka.instance.hostname}:8700/eureka

其中defaultZone是一个魔术字符串后备值为任何不表示首选项的客户端提供服务URL即它是有用的默认值。 通过spring.application.name属性我们可以指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问。

3.4.4 访问服务

启动该工程后再次访问启动工程后http://localhost:8700/可以如下图内容我们定义的服务被成功注册了。

至此Eureka Serve实战案例搭建完成。

上面一行红色粗体内容引起我们的注意。

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

意思紧急!Eureka已经不能确认这些已经启动的实例是否可用由于最近的续订次数小于续订阈值续订期望值为了安全起见实例可用当前这些实例不会删除。

这是为什么呢

出现上面这种情况其实是Eureka进入自我保护模式SELF PRESERVATION MODE。

4、什么自我保护模式

4.1 自我保护原理

我们知道当微服务客户端启动后会把自身信息注册到Eureka注册中心以供其他微服务进行调用。一般情况下当某个服务不可用时一段时间内没有检测到心跳或者连接超时等那么Eureka注册中心就会将该服务从可用服务列表中剔除但是在微服务架构中因为服务数量众多可能存在跨机房或者跨区域的情况因此当某个服务心跳探测失败并不能完全说明其无法正常提供服务而将其剔除并且服务一旦剔除后再重新注册将会重新进行负载均衡等等一系列的操作考虑到性能问题eureka会将不可用的服务暂时断开并期望能够在接下来一段时间内接收到心跳信号而不是直接剔除同时新来的请求将不会分发给暂停服务的实例这就是eureka的保护机制它保护了因网络等问题造成的短暂的服务不可用的实例避免频繁注册服务对整个系统造成影响。

4.2 自我保护触发条件

4.2.1 触发条件

进入自我保护模式的条件如果最近一分钟实际接收到的心跳值Renews除以期望的心跳阈值 Renews threshold小于等于0.85即 Renews/Renews threshold≤0.85。

我们这里 Renews/Renews = 2/3 = 0.7 ≤ 0.85所以触发了以上自我保护提示提示。

下面我们来看下触发自我保护的具体的计算参数含义以及计算逻辑。

4.2.2 Renews threshold

Renews thresholdEureka注册中心期望接收到的心跳值计算方法

服务注册中心不注册自己 1+2*n

服务注册中心注册自己 1+2*(n+1) 。

参数解析

1) 数字1

这个是Eureka框架代码里面写时的最低阈值1意味着没有任何客户端注册阈值也有1。

2) 数字2

这个是最近一分钟接收到的心跳次数Eureka客户端和注册中心心跳检测默认是30s一次那么一分钟就是2次可以通过下面的参数进行调整。

#定义每分钟发送到服务器的更新数 default is 30 也就是每30秒续订一次

eureka.instance.leaseRenewalIntervalInSeconds=30

3) 数字n

这个是客户端的数量个数如果注册中心自己不注册那么有几个客户端n就是几如果注册中心自己也要注册那么就需要把注册中心也加上这是因为在实际生产环境中为了保证注册中心的高可用往往注册中心会搭建集群那么注册中心ABC相互之间也会注册所以就相当于一个客户端。是否注册可以通过下面的代码进行设置。

#是否在Eureka Server中注册默认是true

eureka.client.registerWithEureka=false

4.2.3 Renews

Renews 注册中心实际接收到的心跳值计算方法

服务注册中心不注册自己 2*n

服务注册中心注册自己 2*(n+1)

参数解析

1) 数字2

这个是最近一分钟接收到的心跳次数Eureka客户端和注册中心心跳检测默认是30s一次那么一分钟就是2次可以通过下面的参数进行调整设置代码同上

2) 数字n

这个是客户端的数量个数如果注册中心自己不注册那么有几个客户端n就是几如果注册中心自己也要注册那么就需要把注册中心也加上这是因为在实际生产环境中为了保证注册中心的高可用往往注册中心会搭建集群那么注册中心ABC相互之间也会注册所以就相当于一个客户端。是否注册可以通过下面的代码进行设置设置代码同上。

30.85

0.85这个参数是Eureka默认的一个比值参数代表eureka-server最后一分钟收到的心跳次数小于等于总心跳次数的85%可通过下面的代码进行调整

eureka.server.renewalPercentThreshold=0.85

4.2.4 如何解决

1生成环境

在生产上可以开自注册部署两个server 。

2本地调试

在本机器上测试的时候可以把比值调低比如0.49。

eureka.server.renewalPercentThreshold=0.49

1)关闭自我保护

# 默认值是true

eureka.server.enable-self-preservation=false

说明如果关闭自我保护模式。 在网络/其他问题的情况下这可能无法保护实例到期可能提供不可用的服务给客户端调用。

以上

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring