1. Eureka是什么
Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。
服务注册和发现对于微服务架构是十分重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件。 功能类似于dubbo的zookeeper。
1.1 Eureka和Zookeeper的区别
根据分布式CAP理论,一个分布式系统不能同时满足C(一致性),A(可用性),P(分区容错性)。由于目前技术无法避免两个子网络(区)之间的通信一定成功,所以必须满足P(分区容错)。故只能在C(一致性)和A(可用性)之间选择。
Zookeeper满足CP
zk因为是主备模式,故当Leader节点因为网络故障等原因与其他节点失去联系时,剩余节点会进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。
Eureka满足AP
当向服务注册中心查询服务列表时,我们可以忍受注册中心返回的是几分钟之前的注册信息,但是不能忍受注册中心直接down掉。也就是说,服务注册功能对于可用性的要求要高于一致性。而Eureka设计的时候保证了可用性,Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的正常工作,剩余节点依旧可以提供注册和查询服务。而Eureka Client在向某个Eureka Server注册时发现连接失败,会自动切换到其他节点,只要一台Eureka正常,就能保证注册服务可用(保证可用性)。只不过查到的信息不一定是最新的(不保证强一直性)。除此之外,Eureka还有自我保护机制,如果15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为Eureka Client与Eureka Server出现了网络故障,此时会出现以下几种情况:
- Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。
- Eureka依旧能接受新服务的注册和查询功能,但是不会同步到其他节点上(保证当前节点依旧可用)。
- 当网络稳定时,当前新的实例会被同步到其他节点中。
Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。
2. Eureka的架构
Eureka包含两个组件,Eureka Server和Eureka Client,Eureka Server提供服务注册的功能。
Eureka的架构各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表将会存储所有可用的节点的信息,服务节点的信息可以在界面中直观的看到。EurekaClient是一个Java客户端,用于简化Eureka Server的交互,客户端同时具有一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在项目启动后,将会向Eureka Server发送心跳(默认周期30s)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个节点移除(默认90s)。
系统中的其他微服务,使用Eureka Client连接到Eureka Server并维持心跳。这样系统维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。SpringCloud的一些其他模块(比如Zuul)就可以通过Eureka Server来发现系统中的其他微服务,并执行相关的逻辑。
3. Eureka实战
3.1 Eureka sever注册中心
1. 引入maven依赖
<dependencies>
<!--eureka-server服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
2. yml配置
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka server的域名
client:
register-with-eureka: false #不向注册中心注册自己
fetch-registry: false #false表示自己是注册中心,我的职责就是维护服务实例,而不需要检索服务
service-url:
#Eureka server 服务注册和发现的地址(单机)
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
3. 启动类设置
@SpringBootApplication
@EnableEurekaServer //EurekaServer服务器的启动类,接受其他微服务注册进来
public class MicroservicecloudEureka7001Application {
public static void main(String[] args) {
SpringApplication.run(MicroservicecloudEureka7001Application.class, args);
}
}
启动eureka server后,可以访问http://localhost:7001/ 访问eureka 服务的管理页面。
3.2 Eureka client服务注册
无论是服务提供者需要在Eureka中完成服务的注册,他是Eureka client。
1. 引入maven依赖
<!-- actuator监控信息完善 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--将服务注册到SpringCloud中-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
需要注意的是,在项目的父pom文件中,新增<build>标签。作用就是可以读取src/main/resources
路径下(其实就是配置文件),以@开头以及结尾的参数。
<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>
2. yml配置
Spring:
#注册到Eureka Server微服务名称
application:
name: microservicecloud-provider-8001
eureka:
client:
service-url:
#需要注册的eureka server的地址
defaultZone: http://localhost:7001/eureka
instance:
#微服务节点的名字
instance-id: microservicecloud-provider-8001
#访问路径是否可以显示IP地址
prefer-ip-address: true
# 点击访问地址的微服务说明
info:
app.name: xxx-microservicecloud
company.name: xxx
#获取pom文件中的内容
build.artifactId: @project.artifactId@
build.version: @project.version@
3. 启动类配置
@SpringBootApplication
@MapperScan(basePackages = "com.xxx.mapper")
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
public class DeptProvider8001_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
3.3 Eureka Client服务发现
Eureka server可以提供已注册服务的展示页面。但是如何给服务调用者提供一个API级别的服务发现功能呢?
1. 在Eureka Client启动类上加上@EnableDiscoveryClient //服务发现
@SpringBootApplication
@MapperScan(basePackages = "com.galax.mapper")
@EnableEurekaClient //本服务启动后会自动注册进eureka服务中
@EnableDiscoveryClient //服务发现
public class DeptProvider8001_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
2. 在业务类上便可以使用:
import org.springframework.cloud.client.discovery.DiscoveryClient;
@Resource
private DiscoveryClient discoveryClient;
@RequestMapping(value = "/discovery")
public String discovery(){
//获取所有的服务列表
List<String> services = discoveryClient.getServices();
//获取某个实例的服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("MICROSERVICECLOUD-PROVIDER-8001");
return JSON.toJSONString(instances);
}
3.3 Eureka集群配置
1. 修改hosts文件
C:\Windows\System32\drivers\etc
#新增
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
2. Eureka server是相同的代码,只是yml不同
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com # eureka server的域名
client:
register-with-eureka: false #不向注册中心注册自己
fetch-registry: false #false表示自己是注册中心,我的职责就是维护服务实例,而不需要检索服务
service-url:
#Eureka server 服务注册和发现的地址
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ (单机版配置)
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
3. Eureka Client则向集群server注册服务
Spring:
#注册到Eureka Server微服务名称
application:
name: microservicecloud-provider-8001
eureka:
client:
service-url:
#需要注册到的eureka server的地址
# defaultZone: http://localhost:7001/eureka #单机版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
#微服务节点的名字
instance-id: microservicecloud-provider-8001
#访问路径是否可以显示IP地址
prefer-ip-address: true
# 点击访问地址的微服务说明
info:
app.name: xxx-microservicecloud
company.name: xxx
#获取pom文件的参数$xxx$
build.artifactId: @project.artifactId@
build.version: @project.version@
附录
1. CAP原理
分布式系统最大的难点就是各个节点的状态如何让同步。CAP定理就是这方面的基本定理,也是理解分布式系统的起点。
1. 什么是CAP
-
P:
Partition tolerance
,即分区容错,大多数分布式系统都部署在多个子网络,每个子网络一个区,分区容错的意思就是区间的通信可能失败。例如:一台服务器放在中国,另一台服务器放在美国,这就是两个区,他们之间可能无法通信。
一般来说,分区容错无法避免,因此可以认为CAP中的P总是成立。CAP定理告诉我们,剩下的A和C无法同时做到。 -
C:
Consistency
,即一致性,写操作之后的读操作,每个区上的服务器放回的必须是该值。但是正如P(分区容错)不可避免,若是保证每台服务器的一致性,那么必将牺牲可用性 -
A:
Availability
,即可用性,只要收到用户的请求,服务器必须给出回应。即用户可以选择向A服务器或者B服务器发送读操作。服务器收到请求,就必须立即告诉用户。
2. C和A的矛盾
一致性和可用性,为什么不能同时成立?原因就是P(分区容错)的存在。若要保持一致性,那么服务器之间必须在数据完全同步后,才能返回用户响应;若是保持可用性,那么服务器之间可能存在不一致的数据。
2. Zookeeper的原理
Zookeeper采用的是ZooKeeper Atomic Broadcast(ZAB,ZooKeeper原子广播协议)的协议作为其数据一致性的核心算法。
基于ZAB协议,Zookeeper实现了一种主备模式(Leader、Follower)的系统架构来保证集群中各个副本之间的数据一致性。
1. ZAB协议的介绍
ZAB协议包括两种基本的模式,分别是崩溃恢复和消息广播。在Zookeeper集群启动的过程中,或者Leader服务器出现网络中断,崩溃退出与重启等异常情况,ZAB协议就会进入恢复模式并选举产生新的Leader服务器。需要注意的是:整个过程Zookeeper不可用
。选举产生了新的Leader服务器,同时集群中有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式。其中,状态同步是指数据同步,用来保证集群中存在过半的机器能够和Leader服务器的数据状态保持一致。
崩溃恢复模式包括两个阶段:Leader选举和数据同步。
当集群中有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个集群就可以进入消息广播模式了。
网友评论