Eureka 是什么?
- Eureka 是Spring Cloud的服务治理组件,有三个核心角色: 服务注册中心、服务提供者、服务消费者。Eureka 主管服务注册中心。 是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于dubbo的注册中心比如Zookeeper。
- Netflix 在设计Eureka 时遵守的就是AP原则(CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得)
- Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。
- 系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
三大角色
服务提供者
- “服务提供者” 在启动的时候会通过发送REST请求的方式将自己注册到EurekaServer 上, 同时带上了自身服务的一些元数据信息。Eureka Server接收到这个REST请求之后, 将元数据信息存储在一个双层结构Map中, 其中第一层的key是服务名, 第二层的key是 具体服务的实例名。(我们可以回想一下之前在实现Ribbon负载均衡的例子中, Eureka信 息面板中一个服务有多个实例的清况, 这些内容就是以这样的双层Map形式 存储的。) 在服务注册时, 需要确认一下 eureka.cli ent.register-with-eureka=true 参数是否正确, 该值默认为true。 若设置为false将不会 启动注册操作。
- 两个服务提供者分别注册到了两个不同的服务注册中心上, 也就是说, 它们的信息分别被两个服务注册中心所维护。 此时, 由于服务注册中心之间因 互相注册为服务, 当服务提供者发送注册请求到一个服务注册中心时, 它会将该请求转发 给集群中相连的其他注册中心, 从而实现注册中心之间的服务同步 。 通过服务同步,两个 服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。
- 在注册完服务之后,服务提供者会维护一个心跳用来持续告诉Eureka Server: "我还活 着 ”, 以防止Eureka Server的 “剔除任务 ” 将该服务实例从服务列表中排除出去,我们称 该操作为服务续约(Renew)。 eureka.instance.lease-renewal-interval-in-seconds 参数用于定义服 务续约任务的调用间隔时间,默认为30秒。 eureka.instance.lease-expiration-duration-in-seconds参数用于定义服务失效的时间,默认为90秒。
服务消费者
- 获取服务。 服务注册中心已经注册了 一个服务, 并且该服务有两个实例。 当我们启动 服务消费者的时候, 它会发送一个REST请求给服务注册中心,来获取上面注册的服务清 单 。 为了性能考虑, Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓 存清单会每隔30秒更新 一次。 获取服务是服务消费者的基础,所以必须确保eureka.client.fetch-registry= true参数没有被修改成false, 该值默认为true。若希望修改缓存清单的 更新时间,可 以通过 eureka.client.registry-fetch-interval-seconds= 30参数进行修改, 该参数默认值为30, 单位为秒。
- 服务调用。服务消费者在 获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例 的元数据信息。 因为有这些服务实例的详细信息, 所以客户端可以根据自己的需要决定具 体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均 衡。
- 服务下线。在系统运行过程中必然会面临关闭或重启服务的某个实例的情况, 在服务关闭期间, 我们自然不希望客户端会继续调用关闭了的实例。 所以在客户端程序中, 当服务实例进行 正常的关闭操作时, 它会触发一个服务下线的 REST请求给Eureka Server, 告诉服务注册 中心:“我要下线了” 。 服务端在接收到请求之后, 将该服务状态置为下线(DOWN), 并把 该下线事件传播出去。
服务注册中心
- 失效剔除。 有些时候, 我们的服务实例并不一定会正常下线, 可能由于内存溢出、 网络故障等原 因使得服务不能正常工作, 而服务注册中心并未收到 “服务下线” 的请求。 为了从服务列 表中将这些无法提供服务的实例剔除, Eureka Server在启动的时候会创建一个定时任务, 默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔 除出去。
- 自我保护。Eureka Server 在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%, 如果出现低于的情况(在 单机调试的时候很容易满足, 实际在生产环境上通常是由于网络不稳定导致), Eureka Server会将当前的实例注册信息保护起来, 让这些实例不会过期, 尽可能保护这些注册信 息。 但是, 在这段保护期间内实例若出现问题, 那么客户端很容易拿到实际已经不存在的 服务实例, 会出现调用失败的清况, 所以客户端必须要有容错机制, 比如可以使用请求重 试、 断路器等机制。 由于本地调试很容易触发注册中心的保护机制, 这会使得注册中心维护的服务实例不 那么准确。 所以, 我们在本地进行开发的时候, 可以使用 eureka.server.enable-self-preservation=false 参数来关闭保护机制,以确保注册中心可以将不可用的实例正确剔除。
Eureka 包含两个组件:Eureka Server和Eureka Client
-
Eureka Server 提供服务注册服务
各个节点启动后,会在EurekaServer 中进行注册,这样EurekaServer 中的服务注册表建辉存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到
-
Eureka Client Java客户端
Eureka Client 是一个 Java客户端,用于简化Eureka Server 的交互,客户端同时也丠一个内置的使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server 发送心跳(默认周期是30s)如果Eureka Server 在多个心跳周期内没有接受到某个节点的心跳,EurekaServer 将会从服务注册表中把这个服务节点移除(默认90s)
Eureka 自我保护机制
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,EurekaServer就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以使用eureka.server.enable-self-preservation = false 禁用自我保护模式。
某时刻某一个微服务不可用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存
上面主要是关于Eureka的介绍,下面Base之前构建的服务的生产者和消费者来实现单机版的Eureka
Eureka 服务注册中心模块
新建模块: springcloudDemo-Eureka-7001,具体的使用Maven构建模块的操作方法就不演示了,请查看上面的关联文章。具体项目结构:
POM文件
<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>com.mike.demo</groupId><artifactId>springcloudDemo</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>springcloudDemo-Eureka-7001</artifactId><dependencies><!--eureka-server服务端 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka-server</artifactId></dependency><!-- 修改后立即生效,热部署 --><dependency><groupId>org.springframework</groupId><artifactId>springloaded</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId></dependency></dependencies>
</project>
application.yml 配置文件
server: port: 7001eureka:instance:hostname: eureka7001.com #eureka服务端的实例名称, C:\Windows\System32\drivers\etc 的hosts已经加入映射client:register-with-eureka: false #false表示不向注册中心注册自己。fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务service-url:#单机defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址。
配置Windows hosts文件
打开 C:\Windows\System32\drivers\etc
将域名 eureka7001.com
映射到 127.0.0.1
至于其他操作系统,大家可以百度一下或谷歌,由于之后会有集群所以为了方便设置了域名。
Eureka 主启动类
package com.mike.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer//EurekaServer服务器端启动类,接受其它微服务注册进来
public class EurekaServer7001_App
{public static void main(String[] args){SpringApplication.run(EurekaServer7001_App.class, args);}
}
服务注册中心测试
启动 Eureka 模块
http://eureka7001.com:7001/
这里可以看到,没有任何服务注册进来。
修改服务提供者
服务提供者: springcloudDemo-provider-dept-8001,这个模块在之前我们已经构建完成。请查看文章开口的文章列表。
POM
pom文件添加Eureka 的依赖
<!-- 将微服务provider侧注册进eureka --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-eureka</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><!-- 监控插件--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
父项目POM文件修改
父项目(springcloudDemo)
在POM文件中加入:
<build><finalName>springcloudDemo</finalName><resources><resource><directory>src/main/resources</directory><filtering>true</filtering></resource></resources><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><configuration><delimiters><delimit>$</delimit></delimiters></configuration></plugin></plugins></build>
上面的修改主要是为了使 服务的提供者 设置的服务信息生效即下方的application.yml 修改中的内容:
info:app.name: atguigu-springcloudDemocompany.name: www.atguigu.combuild.artifactId: $project.artifactId$build.version: $project.version$
修改 application.yml
server:port: 8001mybatis:config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径type-aliases-package: com.mike.demo.entities # 所有Entity别名类所在包mapper-locations:- classpath:mybatis/mapper/**/*.xml # mapper映射文件spring:application:name: springcloudDemo-dept datasource:type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包url: jdbc:mysql://XXXXXXXXXX:3306/cloudDB01 # 数据库名称username: rootpassword: XXXXdbcp2:min-idle: 5 # 数据库连接池的最小维持连接数initial-size: 5 # 初始化连接数max-total: 5 # 最大连接数max-wait-millis: 200 # 等待连接获取的最大超时时间eureka:client: #客户端注册进eureka服务列表内service-url: #单机版defaultZone: http://localhost:7001/eurekainstance: # 将服务名称修改 (页面中显示服务名称 原: localhost:springcloudDemo-dept:8001 修改为springcloudDemo-dept8001)instance-id: springcloudDemo-dept8001prefer-ip-address: true
info:app.name: atguigu-springcloudDemocompany.name: www.atguigu.combuild.artifactId: $project.artifactId$build.version: $project.version$
启动类添加Eureka的Enable
@EnableEurekaClient
//本服务启动后会自动注册进eureka服务中
修改完毕,测试
查看服务是否注册进已经开启的Eureka服务器,首先启动Eureka服务器再启动服务的提供者(先有联通运营商后有我们这些联通用户并联网)
查看截图:
红框的查看已经显示了有一个服务注册进入到了Eureka服务器中,上面的红色报错,是因为Eureka自我保护机制导致,长时间没有服务注册。
下面重启所有的服务,查看错误是否消除
- 由上图可以看到,重启Eureka和服务提供者后,Eureka由于自我保护机制出现的错误消失了
- SPRINGCLOUDDEMO-DEPT 是由 application.yml 配置文件中定义的
- springcloudDemo-dept8001 是由 application.yml 配置文件中定义的
- 点击 springcloudDemo-dept8001 可以查看该服务节点的详细信息,这里的详细信息也是在application.yml 中配置的
info:app.name: atguigu-springcloudDemocompany.name: www.atguigu.combuild.artifactId: $project.artifactId$build.version: $project.version$
- 测试服务提供者
Eureka 服务发现
– 对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
服务提供者修改Controller
import org.springframework.cloud.client.discovery.DiscoveryClient;@Autowiredprivate DiscoveryClient client;// Eureka 服务发现测试 @RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)public Object discovery(){List<String> list = client.getServices();System.out.println("**********" + list);List<ServiceInstance> srvList = client.getInstances("MICROSERVICECLOUD-DEPT");for (ServiceInstance element : srvList) {System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t"+ element.getUri());}return this.client;}
启动类添加注解 @EnableDiscoveryClient
测试
重启Eureka 和 provider
输入: http://eureka7001.com:8001/dept/discovery
自此单节点的Eureka 如何部署并使用已经完成了。