16 07 2019

Eureka

官方介绍:

Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers.

Eureka 是一个基于 REST 的服务,主要在 AWS 云中使用, 定位服务来进行中间层服务器的负载均衡和故障转移。  


组成:

Eureka Server 注册中心
Eureka Client  服务注册


注册中心(Eureka Server)作用

它主要记录各个微服务和微服务地址的映射关系,各个微服务都将自己注册到这个注册中心上面,

当微服务之间需要互相调用时,就可以从注册中心上面去发现微服务和进行调用。

举个栗子:我们可以将Eureka Server理解为古代青楼的妈妈,当有失足小姐姐肯定会先给青楼的妈妈登记,当各位要去消费时直接找青楼的妈妈就行了(我要 春香,我要秋月.ing)


Eureka Server  实战

1.打开idea,新建一个项目,点击Next




2.填写好包名、项目名、项目类型,jdk等信息(这个页面网络不好加载不出来的话,切换网络或者重试),点击Next




3.勾选好Eureka Server组件,点击下一步




4.选择好项目存放的路径,点击Finish,idea会自动从Spring官方拉起并构建项目,等待项目构建好




5.构建成功的项目如下




6.看下pom.xml中的依赖,构建Eureka Server 主要是需要 spring-cloud-starter-netflix-eureka-server 这个依赖


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.eureka</groupId>
<artifactId>eureka-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-demo</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


7.启动类中添加@EnableEurekaServer注解,例如


/**
* @author will
* @date 2019/7/16
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaDemoApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaDemoApplication.class, args);
}

}


8.配置 application.yml 文件


spring:
application:
name: spring-eureka-service1

eureka:
client:
register-with-eureka: false # 是否向服务注册中心注册自己,默认为true。
fetch-registry: false # 是否检索发现服务,默认为true。
service-url:
defaultZone: http://localhost:8001/eureka/ # 指定服务注册中心的位置,;多个地址可使用 , 分隔。

instance:
hostname: eureka-service1 # 服务注册中心实例的主机名
lease-renewal-interval-in-seconds: 30 # 客户端向Eureka发送心跳周期(s)
lease-expiration-duration-in-seconds: 90 # Eureka Server接收实例的最后一次发出的心跳后,删除需要等待时间(s)

server:
enable-self-preservation: true # Eureka自我保护模式

server:
port: 8001


启动项目之后我们访问http://localhost:8001/,可以看到如下页面,其中还没有注册任何服务




服务注册(Eureka Client)作用:  

服务提供者,将其信息注册到Eureka Server上面


Eureka Client  实战

Client的创建过程和Server的过程类似,将Server创建过程的第三步改为勾选 Eureka Discovery Client ,其余步骤基本一致






构建成功的client图如下





1.构建成功之后先不要急于写代码,要先确保Client的Spring Boot和SpringCloud的版本和Server的版本一致,我们看下pom.xml文件


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.eureka.eurekaclient</groupId>
<artifactId>eureka-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-client</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!-- web应用 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

</dependencies>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>


2.启动类上加上 @EnableDiscoveryClient 注解,开启该注解使该服务能够被注册中心发现,例如:


/**
* @author will
* @date 2019/7/16
*/
@SpringBootApplication
@EnableEurekaClient
public class EurekaClientApplication {

public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}

}


3.配置 application.yml 文件


eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/
spring:
application:
name: spring-eureka-client

server:
port: 8081


4.先启动Server,再启动Client,然后我们访问 http://localhost:8001/,发现Client已经注册上去了




注意:如果Eureka Client出现启动后自动停止的问题,请在pom.xml中加入如下依赖,并刷新maven.

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>




Eureka集群

注册中心这么关键的服务,如果是单点话,遇到故障就是毁灭性的。在一个分布式系统中,服务注册中心是最重要的基础部分,理应随时处于可以提供服务的状态。为了维持其高可用性,使用集群是很好的解决方案(两台服务器,相互注册,多台服务器,两两之间相互注册即可)


多节点注册中心实战

一般我们的生产环境中,会需要用三台或者三台以上的注册中心,来保证服务的稳定性,我们这里采用三节点演示。


我们先来看单节点和三节点的协作图理解下




三节点Eureka Server的 application.yml 配置文件


spring:
application:
name: spring-eureka-service1

eureka:
client:
register-with-eureka: false # 是否向服务注册中心注册自己,默认为true。
fetch-registry: false # 是否检索发现服务,默认为true。
service-url:
defaultZone: http://localhost:8002/eureka/,http://localhost:8003/eureka/ # 指定服务注册中心的位置,;多个地址可使用 , 分隔。

instance:
hostname: eureka-service1 # 服务注册中心实例的主机名
lease-renewal-interval-in-seconds: 30 # 客户端向Eureka发送心跳周期(s)
lease-expiration-duration-in-seconds: 90 # Eureka Server接收实例的最后一次发出的心跳后,删除需要等待时间(s)

server:
enable-self-preservation: true # Eureka自我保护模式

#server:
# port: 8001

--------------------------------------------------------------
spring:
application:
name: spring-eureka-service2

eureka:
client:
register-with-eureka: true # 是否向服务注册中心注册自己,默认为true。
fetch-registry: false # 是否检索发现服务,默认为true。
service-url:
defaultZone: http://localhost:8001/eureka/,http://localhost:8003/eureka/ # 指定服务注册中心的位置,;多个地址可使用 , 分隔。

instance:
hostname: eureka-service2 # 服务注册中心实例的主机名
lease-renewal-interval-in-seconds: 30 # 客户端向Eureka发送心跳周期(s)
lease-expiration-duration-in-seconds: 90 # Eureka Server接收实例的最后一次发出的心跳后,删除需要等待时间(s)

server:
enable-self-preservation: true # Eureka自我保护模式

#server:
# port: 8002
----------------------------------------------------------------------
spring:
application:
name: spring-eureka-service3

eureka:
client:
register-with-eureka: true # 是否向服务注册中心注册自己,默认为true。
fetch-registry: false # 是否检索发现服务,默认为true。
service-url:
defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/ # 指定服务注册中心的位置,;多个地址可使用 , 分隔。

instance:
hostname: eureka-service3 # 服务注册中心实例的主机名
lease-renewal-interval-in-seconds: 30 # 客户端向Eureka发送心跳周期(s)
lease-expiration-duration-in-seconds: 90 # Eureka Server接收实例的最后一次发出的心跳后,删除需要等待时间(s)

server:
enable-self-preservation: true # Eureka自我保护模式

#server:
# port: 8003


三节点Eureka Client的 application.yml 配置文件  


eureka:
client:
service-url:
defaultZone: http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/
spring:
application:
name: spring-eureka-client

server:
port: 8081


由于我们使用的是idea开发工具进行演示(可以同时启动多个项目),只需要修改Eureka Server的 application.yml和项目的端口即可,点击如图所示进去创建项目




选择相应的项目进行复制,复制之后按如图方式修改启动的端口,因此application.yml中的端口需要注释掉(不会的百度查询idea如何启动多个项目即可)




按照上的 三节点Eureka Server的 application.yml 配置文件 启动一个修改一个配置文件,分别启动三个Eureka Server实例一个Eureka Client实例,分别访问 http://localhost:8001/,http://localhost:8002/,http://localhost:8003/,可以看到他们都两两相互注册了,Client服务也分别注入了三个Eureka Server实例,说明我们的集成配置成功了


http://localhost:8001/  




http://localhost:8002/  



http://localhost:8003/    



遇到的问题


1.运行单节点时,测试 Eureka Server的注销失效服务,于是将Eureka Client停掉,过了lease-expiration-duration-in-seconds: 90 设定的90秒之后,服务依然在注册中心显示?

答:Eureka Server的自我保护模式

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。

但是当网络分区故障发生时,会统计心跳失败的比例,阈值因子默认是0.85,如果阈值比最小值大则表明微服务与Eureka Server之间无法正常通信,这就可能变得非常危险了--因为微服务本身是健康的,此时本不应该注销这个微服务。

Eureka Server通过'自我保护模式'来解决这个问题,当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。

一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

自我保护模式是一种对网络异常的安全保护措施。使用自我保护模式,而已让Eureka集群更加的健壮、稳定。

心跳失败比例 = 期望每分钟收到客户端实例续约的总数 / 最后1分钟收到客户端实例续约的总数

心跳失败比例<85%,触发Eureka Server的自我保护模式



2. eureka.client.register-with-eurekau 要不要配置,区别在哪?

答:eureka.client.register-with-eurekau 的默认值为true,这个配置的意思是,是否向服务注册中心注册自己,一般情况,服务的提供者需要设置为true,服务的调用者设置为false


3. Eureka Client 指定服务注册中心的位置,是把所有的eureka的server地址都写上,还是只需要写一个server就可以了(因为server之间已经相互注册了)?如果写上了所有的server地址,那相当于将每个client服务都往所有的server都添加了一遍,那还配置server间的相互注册有什么意义?

答:看图实测试下



测试过程:

按如图 配置三个Eureka节点,三个节点中都会注册Client,关掉Eureka1,等待90s,Eureka1的网页已经打不开了,Eureka2打开已经没了Eureka1的服务发现但是Client注册信息还在,Eureka3同Eureka2为同样的情况,这说明 Eureka2  还在继续提供注册发现的服务,这样就避免了单点故障后的整体服务发现的瘫痪。假如 Client 只向 Eureka1 提供注册,如果 Eureka1 挂了,Client重启之后就无法注册到 Eureka2  和 Eureka3 了, 这就是为什么要向多个Eureka Server提供注册的原因! 只要自己注册的Eureka Server存活,就能提供服务,再添加 Eureka Server 节点也会被复制注册上去。


4. 如果所有的 Eureka Server 节点全部挂了,Client之间能否继续服务? 

答:能。默认情况下,Eureka Server 同时也是 Client, 多个Eureka Server 实例之间可以通过复制的方法, 来实现服务注册表数据的同步Eureka Client 会缓存服务注册表中的信息,所以 Eureka Client 无须每次调用微服务都要先查询Eureka Server,能有效地缓解Eureka Server的压力,而且即使所有的Eureka Server节点都宕掉,Client 依然可以根据缓存中信息找到服务提供者


以上信息都是本人学习Eureka,过程中的笔记,再此整理加深记忆,如有错误之处,请各位雅正


如果文章对你有用请评论或点个赞,顶上去让更多人看到,少踩坑,谢谢(疯狂暗示)    

延伸阅读
  1. redis分布式锁和续期
发表评论