什么是Eureka?
Eureka是Netflix开发的一种开源服务发现框架,它由两个主要组件组成:Eureka服务器和Eureka客户端。Eureka服务器是一个集中式的服务注册中心,用于管理所有注册的微服务实例。Eureka客户端是一个库,可以嵌入到
微服务中,用于将自身注册到Eurka服务器并发现其他注册的微服务实例。
在Eureka架构中,每个微服务实例都是一个Eureka客户端,并通过发送心跳来告知Eureka服务器它们的存在。
Eureka服务器会维护一个注册表,记录所有注册的微服务实例的信息,包括实例的网络地址、健康状态等。Eurka客户端可以通过查询Eureka服务器的注册表来发现其他注册的微服务实例,并通过负载均衡算法来选择合适的
实例进行服务调用。
Eureka服务端 的Pom文件:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cyk</groupId>
<artifactId>springcloudproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>cloud-eureka</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>cloud-eureka</name>
<description>cloud-eureka</description>
<dependencies>
<!--eureka 服务端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.cyk</groupId>
<artifactId>cloud-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
服务端的配置文件
server:
port: 7001
eureka:
instance:
hostname: localhost # eureka 实例名称
client:
# 不向注册中心注册自己
register-with-eureka: false
# 表示自己就是注册中心,我是维护实例的 不需要检索服务
fetch-registry: false
service-url:
# 地址
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
需要在启动类上面增加注解:@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer //Eureka的注解
public class CloudEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(CloudEurekaApplication.class, args);
}
}
Eureka客户端的POM文件:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.1.7</version>
</dependency>
</dependencies>
客户端的Yml文件
eureka:
client:
# 注册进eureka
register-with-eureka: true
# 从Eureka获取已有的注册信息
fetch-registry: true
# 服务注册和获取服务 的地址
service-url:
defaultZone: http://127.0.0.1:7001/eureka/
客户端主启动类上增加**:@EnableEurekaClient**
@SpringBootApplication
@EnableEurekaClient
public class CloudConsumerOrder80Application {
public static void main(String[] args) {
SpringApplication.run(CloudConsumerOrder80Application.class, args);
}
}
三种使用方式:
1.使用DiscoveryClient
@RestController
@Slf4j
@RequestMapping("/order")
public class OrderController {
private String URL = "http://CLOUD-PAYMENT-SERVICE";
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/getPayment/{id}")
public CommResult getPaymentById(@PathVariable("id") Long id){
//方法一 discoveryClient
List<String> services1 = discoveryClient.getServices();
//获取服务列表
if(!services1.isEmpty()){
//获取指定的服务
List<ServiceInstance> instances = discoveryClient.getInstances("cloud-payment-service");
if(!instances.isEmpty()){
//拼接这个URL
URL = "http://"+instances.get(0).getHost()+":"+instances.get(0).getPort();
log.info(URL);
}
}
return restTemplate.getForObject(URL+"/getPayment/"+id, CommResult.class);
}
}
方法二:loadBalancerClient
@GetMapping("/getPayment/{id}")
public CommResult getPaymentById(@PathVariable("id") Long id){
//可以直接获取到这个服务 方法二 loadBalancerClient
ServiceInstance choose = loadBalancerClient.choose("cloud-payment-service");
//获取IP + 端口
URL = "http://"+choose.getHost()+":"+choose.getPort();
return restTemplate.getForObject(URL+"/getPayment/"+id, CommResult.class);
}
方法三 restTemplate的负载均衡
// 先加负载均衡的注解
@Beanx
@LoadBalanced //负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
//方法三 负载 直接URL配上名字就行了 但是需要加上注释
@GetMapping("/getPayment/{id}")
public CommResult getPaymentById(@PathVariable("id") Long id){
//这个地方可以直接加上eureka上的这个名称
return restTemplate.getForObject("http://CLOUD-PAYMENT-SERVICE/getPayment/"+id, CommResult.class);
}
Eureka集群
? 增加一个模块,代码跟上一个Eureka服务模块类似,Pom文件要进行改动:注册地址要相互注册
server:
port: 7002
# 服务名称 也是 注册到Eureka的名称
spring:
application:
name: eureka7002
eureka:
instance:
hostname: eureka7002
client:
#将自己也注册进去 (实际 这个不注册也OK)
# register-with-eureka: false
# fetch-registry: false
# 注册地址,这两个模块要相互注册,7001注册7002的地址,7002 要注册7001的地址
service-url:
defaultZone: http://localhost:7001/eureka/
其他客户端服务Pom文件修改:
eureka:
client:
# 注册进eureka
register-with-eureka: true
# 从Eureka获取已有的注册信息
fetch-registry: true
service-url:
# defaultZone: http://127.0.0.1:7001/eureka/
# 注册地址修改成两个,同时注册两个地址
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/
Eureka注册图:
为了防止EurekaClient可以正常运行,但是与EurekaServer不通的情况下,EurekaServer不会立即将EurekaClient踢出。
默认情况下,EurekaServer没有收到某个服务的心跳,EurekaServer会注销该实例(默认90秒),但是也有可能是网路故障,其实服务是可以正常使用的。此时其实不应该删除这个服务。Eureka采用自我保护模式(短时间内 丢失了过多的客户端)这个时候Eureka不会注销任何服务。
禁止自我保护
服务端
eureka:
instance:
hostname: eureka7001
client:
service-url:
defaultZone: http://localhost:7002/eureka/
server:
# 禁用自我保护
enable-self-preservation: false
# 心跳时间 2000ms
eviction-interval-timer-in-ms: 2000
客户端(服务)
eureka:
client:
# 注册进eureka
register-with-eureka: true
# 从Eureka获取已有的注册信息
fetch-registry: true
service-url:
# defaultZone: http://127.0.0.1:7001/eureka/
defaultZone: http://127.0.0.1:7001/eureka/,http://127.0.0.1:7002/eureka/
# 显示的主机名称
instance:
instance-id: payment8001
# 显示IP地址
prefer-ip-address: true
# 服务端收到最后一次心跳等待时间上线(默认90s) 超出就踢出
lease-expiration-duration-in-seconds: 1
# 客户端向服务端发送心跳的时间间隔(默认30s)
lease-renewal-interval-in-seconds: 2