一、是什么
Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。Netflix在设计Eureka时遵守AP原则。
二、原理
Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(请对比Zookeeper)。Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。
原理图:
dubbo原理图:
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka中的三大角色:
Eureka Server:提供服务注册和发现
Service Provider:服务提供方将自身服务注册到Eureka,从而使服务消费方能够找到
Service Consumer:服务消费方从Eureka获取注册服务列表,从而能够消费服务
三、Eureka Server服务注册中心搭建
1、在父工程下新建服务注册中心模块microservicecloud-eureka-7001
2、添加依赖:spring-cloud-starter-eureka-server
<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.atguigu.springcloud</groupId>
<artifactId>microservicecloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>microservicecloud-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>
3、配置Eureka:
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端的实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
4、在主启动类上启用EurekaServer:使用@EnableEurekaServer注解,表名这是一个Eureka服务注册中心,若使用@EnableEurekaClient则表明示Eureka的服务提供方
@SpringBootApplication
@EnableEurekaServer // EurekaServer服务器端启动类,接受其它微服务注册进来
public class EurekaServer7001_App {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7001_App.class, args);
}
}
5、测试:http://localhost:7001/
四、将服务提供者(microservicecloud-provider-dept-8001)注册至Eureka
1、引入依赖:spring-cloud-starter-eureka(注意不是spring-cloud-starter-eureka-server,spring-cloud-starter-eureka-server是服务注册的服务端,spring-cloud-starter-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>
2、配置服务注册的地址:告知将服务注册至哪儿(Eureka的地址)
eureka:
client: #客户端注册进eureka服务列表内
service-url:
defaultZone: http://localhost:7001/eureka
3、启用Eureka服务注册客户端:@EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
public class DeptProvider8001_App {
public static void main(String args[]) {
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
4、测试:先启动Eureka Server,再启动服务提供者端,访问服务注册的服务端localhost:7001会看到注册的应用,该应用的名字是在服务提供者端的yml文件中设置的,Eureka将其全部置为大写
五、配置完善
1、主机映射名称修改
①修改前的主机映射名称:由Eureka生成(规则:计算机名:应用名:端口)
②修改客户端应用(microservicecloud-provider-dept-8001)的Eureka实例名称
eureka:
instance:
instance-id: microservicecloud-dept8001
③修改之后:
2、主机ip信息提示:当我们将鼠标放在主机映射名称上的超链接上时,左下角展示服务所在的ip信息
①修改前:显示的是计算机名
②修改客户端应用(microservicecloud-provider-dept-8001)的Eureka实例的ip地址显示方式:默认显示计算机名
eureka:
instance:
prefer-ip-address: true #访问路径显示IP地址,默认显示计算机名
③修改之后:
3、注册的微服务的info信息完善:
①完善之前:我们在点击主机映射名称的超链接时会报404
②修改microservicecloud-provider-dept-8001(服务提供端,同时也是Eureka服务注册的客户端),增加actuator依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
③修改microservicecloud-provider-dept-8001(服务提供端,同时也是服务注册的客户端),在主配置文件中增加info信息配置:这里使用maven插件来读取project.artifactId和project.version的值,因此需在父工程下配置maven插件,见第④步配置(如果不采用变量读取的方式,则没必要进行第④步配置)
info:
app.name: atguigu-microservicecloud
company.name: www.atguigu.com
build.artifactId: $project.artifactId$
build.version: $project.version$
④在父工程下配置maven插件,使maven工程的各模块中能读取到工程中的一些变量,比如③中的变量:表示在src/main/resources文件夹下的配置文件可以读取maven工程的一些变量(比如:project.version),这些配置文件中以$开头和结尾的配置项将作为变量被maven的工程变量填充
<build>
<finalName>microservicecloud</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>
⑤配置好之后测试:点击服务应用注册的超链接就可以看到配置的应用信息
为便于查看浏览器中的json数据,可以在谷歌浏览器上安装一个插件JsonView,详情参考
六、自我保护机制
在访问我们搭建的Eureka Server服务端时有时会出现如下的提示:这是Eureka的自我保护在起作用
服务掉线:
自我保护机制:某时刻某一个微服务不可用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存。
默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该Eureka Server节点就会自动退出自我保护模式。它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
在Spring Cloud中,可以禁用自我保护模式,在Eureka的服务端(microservicecloud-eureka-7001)的主配置文件中配置:
eureka.server.enable-self-preservation = false
七、Eureka服务发现
对于注册到Eureka的微服务,可以在Eureka的客户端通过SpringCloud提供的服务发现接口DiscoveryClient来获取服务的注册信息(所有注册到该Eureka服务端的服务信息)
1、在服务注册客户端使用DiscoveryClient科获取所有服务注册的信息:可以查阅到在Eureka中注册服务的所有应用的信息
@RestController
public class DeptController {
@Autowired
private DiscoveryClient client;
@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
public Object discovery() {
//获取所有的微服务
List<String> services = client.getServices();
System.out.println(">>>>" + services);
//获取具体名称的微服务:相同名称的微服务可能有多个——即所谓的分布式集群
List<ServiceInstance> instances = client.getInstances("MICROSERVICECLOUD-DEPT");
for (ServiceInstance inst : instances) {
System.out.println(
inst.getServiceId() + "\t" + inst.getHost() + "\t" + inst.getPort() + "\t" + inst.getUri());
}
return this.client;
}
}
2、启用服务注册发现:主启动类加注解@EnableDiscoveryClient
@SpringBootApplication
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient //启用服务注册的发现
public class DeptProvider8001_App {
public static void main(String args[]) {
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
3、可访问localhost:8001/dept/discovery接口进行测试
4、在消费者端通过RestTemplate调用服务端接口
@RestController
public class DeptController_Consumer {
private static final String REST_URL_PREFIX = "http://localhost:8001";
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/discovery")
public Object discovery() {
return restTemplate.getForObject(REST_URL_PREFIX + "/dept/discovery", Object.class);
}
}
问题
:目前为止消费端依然是采用RestTemplate的方式来调用的服务端接口,并没有调用Eureka中注册的服务,那服务注册有什么用呢?在Ribbon章节的[Ribbon配置初步]中会有讲解。
5、访问消费者端
八、Eureka集群配置
1、搭建集群环境:参照microservicecloud-eureka-7001搭建microservicecloud-eureka-7002和microservicecloud-eureka-7003,即搭建Eureka集群
2、复制microservicecloud-eureka-7001的pom中的依赖至microservicecloud-eureka-7002和microservicecloud-eureka-7003
3、复制microservicecloud-eureka-7001的主启动类至microservicecloud-eureka-7002和microservicecloud-eureka-7003,并修改主启动类的名字
4、修改映射配置,找到hosts文件,添加以下配置:将三个域名映射到同一个地址
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
5、修改集群中的三个项目的主配置文件,让集群中的各个机器之间手牵手:主要是修改hostname和defaultZone的值,hostname的值与hosts文件保持一致,defaultZone的值使各个Eureka机器手牵手
microservicecloud-eureka-7001的application.yml:
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端的实例名称
client:
register-with-eureka: false
fetch-registry: false
service-url:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
microservicecloud-eureka-7002的application.yml:
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端的实例名称
client:
register-with-eureka: false
fetch-registry: false
service-url:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
microservicecloud-eureka-7003的application.yml:
server:
port: 7003
eureka:
instance:
hostname: eureka7003.com #eureka服务端的实例名称
client:
register-with-eureka: false
fetch-registry: false
service-url:
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
6、想把微服务发布到上面的eureka集群中,需要修改eureka客户端(microservicecloud-provider-dept-8001)的eureka配置,主要是修改defaultZone的值:之前是单机版,只写一个值;现为集群,应写集群的每一个地址,以逗号隔开
eureka:
instance:
instance-id: microservicecloud-dept8001
prefer-ip-address: true
client:
service-url:
#defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ #集群
7、测试:将集群中的三台机器(此处为三个项目)和eureka客户端启动,访问任意一个eureka服务,会看到以下画面
SpringCloud中微服务向Eureka注册服务的时候是以应用为单位注册的,而dubbo中微服务向zookeeper注册服务的时候是以接口为单位的。
九、Eureka对比Zookeeper
1、CAP原则:最多只能同时较好的满足其中的两个
C:Consistency——强一致性
A:Availability——可用性
P:Partition tolerance——分区容错性
2、Zookeeper保证的是CP,Eureka保证的是AP
著名的CAP理论指出,一个分布式系统不可能同时满足C(强一致性)、A(可用性)、P(分区容错性),由于分区容错性P在分布式系统中是必须要保证的,因此我们只能在A和C之间进行权衡:Zookeeper保证的是CP,Eureka保证的是AP。
①Zookeeper保证CP:
②Eureka保证AP: