title: Eureka
date: 2022-02-21 14:14:55
categories: springcloud
ps:因换Typora版本大量图片丢失。寄
Eureka 工作原理上节内容为大家介绍了,注册中心 Eureka 产品的使用,以及如何利用 Eureka 搭建单台和集群的注册中心。这节课我们来继续学习 Eureka,了解它的相关概念、工作流程机制等。
Eureka 作为 Spring Cloud 体系中最核心、默认的注册中心组件,研究它的运行机制,有助于我们在工作中更好地使用它。
Eureka 核心概念回到上节的服务注册调用示意图,服务提供者和服务的消费者,本质上也是 Eureka Client 角色。整体上可以分为两个主体:Eureka Server 和 Eureka Client。
Eureka Server:注册中心服务端
注册中心服务端主要对外提供了三个功能:
服务注册
服务提供者启动时,会通过 Eureka Client 向 Eureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表
提供注册表
服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表
同步状态
Eureka Client 通过注册、心跳机制和 Eureka Server 同步当前客户端的状态。
Eureka Client:注册中心客户端
Eureka Client 是一个 Java 客户端,用于简化与 Eureka Server 的交互。Eureka Client 会拉取、更新和缓存 Eureka Server 中的信息。因此当所有的 Eureka Server 节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者,但是当服务有更改的时候会出现信息不一致。
Register: 服务注册
服务的提供者,将自身注册到注册中心,服务提供者也是一个 Eureka Client。当 Eureka Client 向 Eureka Server 注册时,它提供自身的元数据,比如 IP 地址、端口,运行状况指示符 URL,主页等。
Renew: 服务续约
Eureka Client 会每隔 30 秒发送一次心跳来续约。 通过续约来告知 Eureka Server 该 Eureka Client 运行正常,没有出现问题。 默认情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的续约,Server 端会将实例从其注册表中删除,此时间可配置,一般情况不建议更改。
服务续约任务的调用间隔时间,默认为30秒
eureka.instance.lease-renewal-interval-in-seconds=30
服务失效的时间,默认为90秒。
eureka.instance.lease-expiration-duration-in-seconds=90
————————————————
转载自:
原文链接:https://blog.csdn.net/qwe86314/article/details/94552801
<!-- Eureka Server端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
3.写yml
server:
port: 7001
eureka:
instance:
hostname: localhost #eureka服务端实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己端就是注册中心,我的职责就是去维护服务实例,并不需要去检索服务
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4.主启动
@EnableEurekaServer表示标记为注册中心
打开localhost:7001出现该界面表示配置成功
provider注册(client端) 1.建module 2.改pom<!-- Eureka Client端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.写yml
#Eureka
eureka:
client:
register-with-eureka: true #表示将自己注册金EurekaServer 默认为true
fetch-registry: true #是佛从EUR额卡Server抓取已有注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://localhost:7001/eureka
4.主启动
@EnableEurekaClient标记为Client端
5.业务类 6.打开注册中心看看是否注册名字要配置
consumer注册(client端) 1.建module 2.改pom<!-- Eureka Client端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.写yml
#Eureka
eureka:
client:
register-with-eureka: true #表示将自己注册金EurekaServer 默认为true
fetch-registry: true #是佛从EUR额卡Server抓取已有注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://localhost:7001/eureka
4.主启动
@EnableEurekaClient标记为Client端
5.业务类Dao层:
@Mapper
public interface PaymentDao extends BaseMapper<Payment> {
}
Entities
/**
* @author BDsnake
* @description 主实体Payment
* @since 2022/1/14 15:06
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {
private Long id;
private String serial;
}
/**
* @author BDsnake
* @description CommonResult
* @since 2022/1/14 15:11
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult <T>{
private Integer code;
private String message;
private T data;
public CommonResult(Integer code, String message) {
this.code = code;
this.message = message;
}
}
Controller
/**
* @author BDsnake
* @description PaymentController
* @since 2022/1/14 15:31
*/
@Slf4j
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@Value("${server.port}")
private String server_port;
@Resource
private DiscoveryClient discoveryClient;
@PostMapping("/payment/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("******插入结果:"+result);
if (result > 0){
return new CommonResult(200,"插入数据库成功,serverPort:"+server_port,payment);
}else {
return new CommonResult(444,"插入数据库失败",null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentById(@PathVariable("id") Long id){
Payment payment = paymentService.getPaymentById(id);
log.info("******查询结果:"+payment);
if (payment != null){
// System.out.println(payment);
// System.out.println("233");
return new CommonResult(200,"查询成功,serverPort:"+server_port,payment);
// return null;
}else {
return new CommonResult(444,"没有找到对应记录,查询ID:"+id,null);
}
}
Eureka集群搭建 参考cloud-eureka-server7001 新建cloud-eureka-server7002 改pom 修改映射配置
找到C:\Windows\System32\drivers\etc下的hosts文件
用不同的端口号来映射同一个地址
##########################Springcloud 2020.1.2###################
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
写yml(以前单机)
7001指向7002 7002指向7001
server:
port: 7002
eureka:
instance:
hostname: eureka7002.com #eureka服务端实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己端就是注册中心,我的职责就是去维护服务实例,并不需要去检索服务
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7001.com:7001/eureka/
server:
port: 7001
eureka:
instance:
hostname: eureka7001.com #eureka服务端实例名称
client:
register-with-eureka: false #false表示不向注册中心注册自己
fetch-registry: false #false表示自己端就是注册中心,我的职责就是去维护服务实例,并不需要去检索服务
service-url:
#设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
主启动
@EnableEurekaServer
测试
修改消费者和提供者的配置文件yml
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com/7002/eureka
测试
- 启动7001/7002
- 启动8001
- 启动80
- http://localhost/consumer/payment/get/123
抄8001
写yml抄8001,改端口号
主启动抄
业务类抄
修改controller因为有多个提供者,为了区别是哪个提供者提供的服务,需要返回端口号来区分
//端口号
@Value("${server.port}")
private String server_port;
修改80端口的url
之前是写死的方式(单机模式),在运用分布式时url不需要写死,应该在注册中心找到服务名称写上去
对外暴露的由地址变成微服务名称
// 单机版url
// public static final String PAYMENT_URL = "http://localhost:8001";
// 集群版url(利用了分布式)
public static final String PAYMENT_URL = "http:CLOUD-PAYMENT-SERVICE";
添加负载均衡
使用@LoadBalanced注解赋予RestTemplate负载均衡的功能
Actuator微服务信息完善(选) 主机名称:服务名称修改不手动配置时,服务名称很抽象、冗长,不便使用
只需要在对应的服务的yml文件中添加一条配置
# 配置在Eureka中的服务名称
eureka:
instance:
instance-id: payment8001
访问信息有IP信息提示
默认选中服务的时候无具体ip信息提示
只需对应yml下添加一条配置
# 配置具体IP地址显示
eureka:
instance:
prefer-ip-address: true
注意健康检查的依赖需要引入才能生效
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
服务发现Discovery
- 对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
-
修改cloud-provider-payment8001的Controller
@Resource private DiscoveryClient discoveryClient;
注意包别导错,要用spring-cloud包下的
写一个服务
@GetMapping("/payment/discovery") public Object discovery(){ List<String> services = discoveryClient.getServices(); for (String element : services) { log.info("********element:"+element); } // 根据名称获得微服务的信息 List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE"); for (ServiceInstance instance : instances) { log.info(instance.getServiceId()+"\t"+instance.getHost()+"\t"+instance.getPort()+"\t"+instance.getUri()); } return this.discoveryClient; }
-
8001主启动类
主启动类加注解
@EnableDiscoveryClient
- 自测
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 Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务
(某一时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该服务的信息进行保存)【属于CAP里的AP分支】
如果在Eureka Server的首页看到以上这段提示,则说明Eureka进入了保护模式
为什么会产生Eureka自我保护机制?为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除
什么是自我保护模式?默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生时(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了,因为微服务本身其实是健康的,此时本不应该注销这个微服务,Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式
如何关闭自我保护机制绝情模式
server:
enable-self-preservation: false