Eureka服务注册、发现、集群
1、什么是Eureka
- Eureka:怎么读?
- Netflix在设计Eureka时,遵循的就是AP原则
- Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper

2、原理讲解
Eureka的基本架构
- SpringCloud封装了NetFlix公司开发的Eureka模块来实现服务注册和发现(对比Zookeeper)
- Eureka采用了C-S的架构设计,EurekaServer作为服务注册功能的服务器,他是服务注册中心
- 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑;
Eureka包含两个组件: Eureka Server 和 Eureka Client。
Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会村粗所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除掉(默认周期为90秒)
三大角色
- Eureka Server:提供服务的注册于发现。
- Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到。
- Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务。
3、环境搭建
1、导入依赖
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.allen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-eureka-7001</artifactId>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
2、编写配置文件
application.yml
server:
port: 7002
# eureka配置
eureka:
instance:
hostname: localhost # eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向注册中心注册自己
fetch-registry: false # false表示自己为注册中心
service-url: # 监控访问地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3、开启这个功能
@EnableEurekaServer
4、配置类
package com.allen.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author Allen
* @date 2021/1/8 14:49
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
5、测试
在浏览器地址栏输入: http://localhost:7002/ , 出现如下界面

注:若遇到无法启动的情况,可通过降级 springboot 和 springcloud 的版本依赖解决。
附:dubbo监控界面
服务注册
1、导入依赖
首先在 8001 提供者端口,导入 Eureka 依赖
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">
<parent>
<artifactId>springcloud</artifactId>
<groupId>com.allen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-dept-8001</artifactId>
<dependencies>
<!--我们需要在此模块用到另一个模块的实体类,需要导入-->
<dependency>
<groupId>com.allen</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- 热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
</project>
2、编写配置文件
在 8001的 application.yml, 编写 eureka 配置
server:
port: 8001
# mybatis配置
mybatis:
type-aliases-package: com.allen.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
# spring配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 1005
# eureka配置, 服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://localhost:7002/eureka/
3、开启这个功能
在8001提供者启动类中开启Eureka: @EnableEurekaClient
package com.allen.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author Allen
* @date 2021/1/7 19:39
*/
//启动类
@SpringBootApplication
@EnableEurekaClient //在启动服务后,自动注册到Eureka中
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
4、测试
首先启动 7002 注册中心服务,然后启动 8001 提供者服务

信息配置
1、导入依赖
在 8001 服务端口,导入 spring-boot-starter-actuator
<!--actuator完善监控信息-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.4.1</version>
</dependency>
2、配置info
在 8001 服务的配置文件中,编写
# info配置
info:
app.name: allen-springcloud
company.name: hlgao666
3、测试
点击下图任意一个链接,

可看到输出如下信息:

自我保护机制
上图中红色字体即自我保护机制警告!
一句话总结: 某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存!
- 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServe一一实例(默认90秒)。但是当网络分区故障发生时,微服务与EureKa之间无法止吊通,以得竹力制应能决这常危险了–因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制解决–当EurekaServer节点在短时间内丢失过多客户端时(可能反生网络分区故障)那么这个节点就会进入自我保护模式。一旦进入该模式,EureKaServVer就会保护服务注册节点的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
- 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式, 即宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着
- 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka
集群更加的健壮和稳定 - 在SpringCloud中,可以使用
eureka.server.enable-self-preservation = false禁用自我保护模式【不推荐关闭自我保护机制】
服务发现
1、修改 8001 服务的 controller
package com.allen.springcloud.deptController;
import com.allen.springcloud.pojo.Dept;
import com.allen.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author Allen
* @date 2021/1/7 19:30
*/
//提供Restful服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
//获取一些配置的信息,得到具体的微服务
@Autowired
private DiscoveryClient client;
@PostMapping("/dept/add")
public boolean addDept(Dept dept){
return deptService.addDept(dept);
}
@GetMapping("/dept/get/{id}")
public Dept queryDeptById(@PathVariable("id") Long id){
return deptService.queryDeptById(id);
}
@GetMapping("/dept/list")
public List<Dept> queryAll(){
return deptService.queryAll();
}
//注册进来的微服务,获取一些消息
@GetMapping("/dept/discovery")
public Object discovery(){
//获取微服务列表清单
List<String> services = client.getServices();
System.out.println(services);
//得到一个具体的微服务信息,通过微服务applicationName
List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(instance);
}
return this.client;
}
}
2、开启注解 @EnableDiscoveryClient 服务发现
package com.allen.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author Allen
* @date 2021/1/7 19:39
*/
//启动类
@SpringBootApplication
@EnableEurekaClient //在启动服务后,自动注册到Eureka中
@EnableDiscoveryClient //服务发现
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class,args);
}
}
3、测试
重新 build 8001 服务,访问 http://localhost:8001/dept/discovery
弹出如下界面:

集群
为防止一个服务中心故障,需要开启多个服务中心,每个服务中心关联另外的服务中心。

1、修改服务端实例名称(模拟多个服务中心)

2、编写3个服务端,直接从7001拷贝
包括 application.yml、pom.xml、启动类
3、修改 application.yml
7002 application.yml
server:
port: 7002
# eureka配置
eureka:
instance:
hostname: eureka7002.com # eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向注册中心注册自己
fetch-registry: false # false表示自己为注册中心
service-url: # 监控访问地址
# 单机: http://${eureka.instance.hostname}:${server.port}
# 集群:(关联)
defaultZone: http://eureka7003.com:7003, http://eureka7004.com:7004
7003 application.yml
server:
port: 7003
# eureka配置
eureka:
instance:
hostname: eureka7003.com # eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向注册中心注册自己
fetch-registry: false # false表示自己为注册中心
service-url: # 监控访问地址
defaultZone: http://eureka7002.com:7002, http://eureka7004.com:7004
7004 application.yml
server:
port: 7004
# eureka配置
eureka:
instance:
hostname: eureka7004.com # eureka服务端的实例名称
client:
register-with-eureka: false # 表示是否向注册中心注册自己
fetch-registry: false # false表示自己为注册中心
service-url: # 监控访问地址
defaultZone: http://eureka7002.com:7002, http://eureka7003.com:7003
8001 application.yml
defaultZone: 关联3个服务中心
server:
port: 8001
# mybatis配置
mybatis:
type-aliases-package: com.allen.springcloud.pojo
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
# spring配置
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource #数据源
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 1005
# eureka配置, 服务注册到哪里
eureka:
client:
service-url:
defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/, http://eureka7004.com:7004/eureka/
instance:
instance-id: springcloud-provider-dept8001 #修改Eureka的默认描述信息
# info配置
info:
app.name: allen-springcloud
company.name: hlgao666
4、测试
依次开启7002、7003、7004、8001服务,访问 7002 端口

点击上图的 eureka7004.com,跳转后界面如图

依次再访问 http://eureka7002.com:7002/ 和 http://eureka7003.com:7003/ 时,是看不到服务的注册,虽然这3个注册中心构成了一个集群,但是只有当一个垮了之后,才会去访问下一个集群节点。 Eureka Client 在发送注册请求时,会按照 Eureka Server 集群节点 serviceUrlList 顺序逐个去尝试,如果有一个请求成功了,那么直接返回response ,不再去向其他节点请求。
在本例中服务注册请求在 eureka7004 中注册成功,即 eureka7004 对应的 Eureka Server服务的状态是UP,则不会向另外两个节点(eureka7002,eureka7003)发送请求,相应地页面上也就没有显示。一旦停止 eureka7004 服务注册中心,则 dept-8001 服务会向 eureka7002 发送注册请求。
可参考client重试机制: https://blog.csdn.net/qq_36960211/article/details/85273392