3. Netflix.Eureka
3.1 简介
- Eureka( [juˈriːkə] )遵循 AP 原则。
- Eureka 是 Netflix 的核心模块,基于 REST 实现云端中间层服务发现和故障转移,用于定位服务。
- 服务注册与发现使 consumer 不需要修改服务调用的配置文件,只需要使用服务的标识符,就可以访问服务。类似于 Dubbo 的注册中心,如 zookeeper。
3.2 架构
3.3 环境搭建
(1) 创建一个 maven 模块作为 eureka 注册中心
springcloud-eureka-7001
● 导入依赖
<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>
● 编写配置文件
server:
port: 7001
eureka:
instance:
hostname: localhost # Eureka 服务端实例名
client:
register-with-eureka: false # 是否向注册中心注册
fetch-registry: false # false 表示本身为注册中心
service-url: # 设置服务的 url(监控页面)
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
● 编写主类
// 启动后访问 http://localhost:7001/
@SpringBootApplication
// 标识为 eureka 服务端,可接受其他服务的注册
@EnableEurekaServer
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class, args);
}
}
3.4 服务注册
将 springcloud-provider-dept-8001 服务注册到 eureka 注册中心
(1) 导入依赖
<!-- 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>
(2) 配置 eureka 注册服务的地址
# eureka
eureka:
client:
service-url:
# 注册中心的地址
defaultZone: http://localhost:7001/eureka/
instance:
# 修改服务实例描述
instance-id: springcloud-provider-dept8001
(3) 启动类开启 eureka 客户端注册
// 服务启动后注册到 eureka 注册中心
@EnableEurekaClient
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class, args);
}
}
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.
紧急情况!EUREKA可能错误地声称实例在未启动时已启动。续订小于阈值,因此实例不会为了安全而过期。
Eureka 保护机制
某微服务不可用时,eureka 不清理其保存在 注册中心的信息,防止微服务本身没有问题的情况下,服务信息被清理。
(4) 完善监控信息
● 导入依赖
<!--actuator-->
<!--完善监控信息-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
● 添加配置
# info
info:
app.name: why-springcloud
company.name: blog.why.com
(5) 服务发现
调整 springcloud-provider-dept-8001 服务
● 添加控制器
@Autowired
// org.springframework.cloud.client.discovery.DiscoveryClient
private DiscoveryClient discoveryClient;
/**
* 发现并获取微服务信息
* @return
*/
@RequestMapping("/dept/discovery")
public Object discovery() {
// 获取微服务列表的清单
List<String> services = discoveryClient.getServices();
System.out.println("discovery services => " + services);
// 通过 ApplicationName 获取服务信息
List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
for (ServiceInstance instance : instances) {
System.out.println(
"host => " + instance.getHost() + "\n" +
"port => " + instance.getPort() + "\n" +
"url => " + instance.getUri() + "\n" +
"serviceId = > " + instance.getServiceId()
);
}
return this.discoveryClient;
}
● 主类添加服务发现注解
// 服务启动后注册到 eureka 注册中心
@EnableEurekaClient
// 服务发现
@EnableDiscoveryClient
@SpringBootApplication
public class DeptProvider_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProvider_8001.class, args);
}
}
● 访问控制器
http://localhost:8001/dept/discovery
{"discoveryClients":[{"services":["springcloud-provider-dept"],"order":0},{"services":[],"order":0}],"services":["springcloud-provider-dept"],"order":0}
3.5 模拟集群环境配置
(1) 添加微服务
● 创建两个 maven 模块作为集群
springcloud-eureka-7002
springcloud-eureka-7001
springcloud-eureka-7003
● 导入依赖
<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>
● 修改配置文件
server:
port: 7002
eureka:
instance:
# Eureka 服务端实例名
hostname: eureka7002.com
client:
# 是否向注册中心注册
register-with-eureka: false
# false 表示本身为注册中心
fetch-registry: false
# 设置服务的 url(监控页面)
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/
server:
port: 7003
eureka:
instance:
# Eureka 服务端实例名
hostname: eureka7003.com
client:
# 是否向注册中心注册
register-with-eureka: false
# false 表示本身为注册中心
fetch-registry: false
# 设置服务的 url(监控页面)
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
● 创建启动类
// 启动后访问 http://localhost:7002/
@SpringBootApplication
// 标识为 eureka 服务端,可接受其他服务的注册
@EnableEurekaServer
public class EurekaServer_7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7002.class, args);
}
}
// 启动后访问 http://localhost:7003/
@SpringBootApplication
// 标识为 eureka 服务端,可接受其他服务的注册
@EnableEurekaServer
public class EurekaServer_7003 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7003.class, args);
}
}
(2) 配置域名映射(模拟多终端注册)
● 添加 hosts 配置
-
路径:C:\Windows\System32\drivers\etc\hosts
-
配置
#Eureka 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.com
(3) 注册服务
● 修改 8001 服务的 eureka 配置
# application.yml
# eureka
eureka:
client:
service-url:
# 注册中心的地址
# 将此服务注册到下面三个注册中心中
defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/,http://localhost:7003/eureka/
instance:
# 修改服务实例描述
instance-id: springcloud-provider-dept8001
3.6 CPA 原则及对比 zookeeper
(1) CPA 原则
-
“C”是指一致性,
- 即当一个Process(过程)修改了某个数据后,其他Process读取这是数据是,得到的是更新后的数据,但并不是所有系统都 可以做到这一点。
- 在一些并非严格要求一致性的系统中,后来的Process得到的数据可能还是修改之前的数据,或者需要等待一定时间后才能得到修改 之后的数据,这被成为“弱一致性”,最经典的应用就是DNS系统。当用户修改了DNS配置后,往往不会马上在全网更新,必定会有一个延迟,这个延迟被称为 “不一致窗口”,它的长度取决于系统的负载、冗余的个数等因素。
- 对于某些系统而言,一旦写入,后面读取的一定是修改后的数据,如银行账户信息,这被称为 “强一致性”。
-
“A”是指可用性。
- 即系统总是能够为用户提供连续的服务能力。
- 当用户发出请求是,系统能给出响应(成功或者失败),而且是立即给出响应,而不是等待其他事情完成才响应。如果需要等待某件事情完成才响应,那么“可用性”就不存在了。
-
“P”是指容错性。
- 任何一个分布式计算系统都是由多个节点组成的。在正常情况下,节点与节点之间的通信是正常的。但是在某些情况下,节点之间的通信会 断开,这种断开成为“Partition”。在分布式计算的实现中,Partition是很常见的,因为节点不可能永远不出故障,尤其是对于跨物理地区的 海量存储系统而言,而容错性则可以保证如果只是系统中的部分节点不可用,那么相关的操作仍旧能够正常完成。
参考: 分布式计算的重要原则——CPA理论_dq_cc的博客-CSDN博客
(2) 对比 zookeeper
- CAP理论告诉我们,一个分布式系统不可能同时满足以下三种
一致性(C:Consistency)
可用性(A:Available)
分区容错性(P:Partition Tolerance)
这三个基本需求,最多只能同时满足其中的两项,因为P是必须的,因此往往选择就在CP或者AP中。
-
在此ZooKeeper保证的是CP
-
分析:可用性(A:Available)
-
不能保证每次服务请求的可用性。任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper不能保证服务可用性。
-
进行leader选举时集群都是不可用。在使用ZooKeeper获取服务列表时,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。所以说,ZooKeeper不能保证服务可用性。
-
参考: ZooKeeper和CAP理论及一致性原则_架构师专栏的博客-CSDN博客