1.eureka简介
1.1 什么是eueka
Eureka
是一个服务注册与发现框架,是 Netflix 开源的注册中心组件,分为 Eureka Client 和 Eureka Server
- Eureka-Server :通过 REST 协议暴露服务,提供应用服务的注册和发现的功能。
- Application Server :应用服务提供者,内嵌 Eureka-Client ,通过它向 Eureka-Server 注册自身服务。
- Application Client :应用服务消费者,内嵌 Eureka-Client ,通过它从 Eureka-Server 获取服务列表
1.2 eureka核心概念
服务注册 Register:当 Eureka
客户端向 Eureka Server
注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等。
服务续约 Renew:Eureka
客户会每隔30秒(默认情况下)发送一次心跳来续约。 通过续约来告知 Eureka Server
该 Eureka
客户仍然存在,没有出现问题。 正常情况下,如果 Eureka Server
在90秒没有收到 Eureka
客户的续约,它会将实例从其注册表中删除。
获取注册列表信息 Fetch Registries: Eureka
客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。每次返回注册列表信息可能与 Eureka
客户端的缓存信息不同, Eureka
客户端自动处理。如果由于某种原因导致注册列表信息不能及时匹配,Eureka
客户端则会重新获取整个注册表信息。 Eureka
服务器缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka
客户端和 Eureka
服务器可以使用JSON / XML格式进行通讯。在默认的情况下 Eureka
客户端使用压缩 JSON
格式来获取注册列表的信息。
服务下线 Cancel:Eureka客户端在程序关闭时向Eureka服务器发送取消请求。 发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:DiscoveryManager.getInstance().shutdownComponent();
服务剔除 Eviction: 在默认的情况下,当Eureka客户端连续90秒(3个续约周期)没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。
项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用
Github地址:https://github.com/plasticene/plasticene-boot-starter-parent
Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent
微信公众号:Shepherd进阶笔记
2.eureka使用
2.1 搭建eureka注册中心
搭建eureka注册服务中心很简单,创建一个spring boot项目,引入eureka server依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 Spring Cloud Netflix Eureka Server 相关依赖,将 Eureka 作为注册中心的服务器,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
然后创建配置文件application.yml:
server:
port: 8761 # 设置 Eureka-Server 的端口
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false # 不注册到 Eureka-Server,默认为 true
fetch-registry: false # 不从 Eureka-Server 获取注册表,默认为 true
然后再启动类上添加注解@EnableEurekaServer
声明启动eureka server就可以了,启动项目之后访问http://127.0.01:8761
这就是eureka server注册中心前台界面,可以看到没有任何实例注册进来,因为我们还没有开始注册。
代码地址:https://github.com/ShepherdZFJ/shepherd-example/tree/main/eureka-server
2.2 搭建服务提供者
创建服务提供者项目:erueka-provider。注意这里服务提供者也可以是服务消费者,因为该服务把自己注册到eureka server中心,可以让其他服务通注册中心发现它、调用它,反过来该服务也可以从注册中心发现其他服务、调用其他服务。
引入依赖:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- 引入 Spring Cloud Netflix Eureka Client 相关依赖,将 Eureka 作为注册中心的客户端,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
添加测试接口代码,方便其他服务调用
package com.shepherd.eureka;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
// @EnableDiscoveryClient 注解,开启 Spring Cloud 的注册发现功能。不过从 Spring Cloud Edgware 版本开始,
// 实际上已经不需要添加 @EnableDiscoveryClient 注解,只需要引入 Spring Cloud 注册发现组件,就会自动开启注册发现的功能
@EnableDiscoveryClient
public class EurekaProviderApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
@RestController
@Slf4j
static class TestController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/provider")
public String test(String name) {
log.info("我被调用了, {}", serverPort);
return "provider:" + name;
}
}
}
代码地址:https://github.com/ShepherdZFJ/shepherd-example/tree/main/eureka-provider
2.3 搭建服务消费者
搭建流程和服务提供者的依赖完全一样,无论是服务消费者还是提供者,都是eureka client角色注册到eureka server中心
添加测试消费代码,调用服务提供者接口:
package com.shepherd.eureka;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.List;
@SpringBootApplication
// @EnableDiscoveryClient 注解,开启 Spring Cloud 的注册发现功能。不过从 Spring Cloud Edgware 版本开始,
// 实际上已经不需要添加 @EnableDiscoveryClient 注解,只需要引入 Spring Cloud 注册发现组件,就会自动开启注册发现的功能
// @EnableDiscoveryClient
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@RestController
@Slf4j
static class TestController {
@Resource
private DiscoveryClient discoveryClient;
@Resource
private RestTemplate restTemplate;
@Resource
private LoadBalancerClient loadBalancerClient;
/**
* 当我们关闭eureka-provider服务之后,我们我有可能还能获取其服务实例信息,只是通过该服务实例调接口会报错
* 因为 Eureka-Client 是每 30 秒定时轮询获取增量变化的注册表,从而更新本地的服务实例缓存。
* 因此,这里还是会去请求已关闭的服务提供者。这个一定要注意!!!
* 当30s之后,服务实例表在本地更新了,那么就没有该服务了
* @param name
* @return
*/
@GetMapping("/consumer")
public String hello(String name) {
// <1> 获得服务 `demo-provider` 的一个实例
// 获取服务 `demo-provider` 对应的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("eureka-provider");
// // 选择第一个
// ServiceInstance instance = instances.size() > 0 ? instances.get(0) : null;
ServiceInstance instance = loadBalancerClient.choose("eureka-provider");
// <2> 发起调用
if (instance == null) {
throw new IllegalStateException("获取不到实例");
}
String targetUrl = instance.getUri() + "/provider?name=" + name;
log.info("loadBalancerClient选择的是:{}", targetUrl);
String response = restTemplate.getForObject(targetUrl, String.class);
// 返回结果
return "consumer:" + response;
}
}
}
这里为了方便快速,就没有使用feign
组件进行远程调用,这里我们提供了两种方式的代码,分别基于 DiscoveryClient 和 LoadBalancerClient,直接获得服务 demo-provider
的一个实例,然后通过restTemplate
调用接口
LoadBalancerClient 的服务实例列表,是来自 DiscoveryClient 提供的,然后再提供负载均衡能力。
代码地址:https://github.com/ShepherdZFJ/shepherd-example/tree/main/eureka-consumer
当服务提供者、服务消费者项目启动之后,你会看到eureka server注册中心前台界面如下:
可以看到服务提供者、消费者都注册进来了,这里我用不同端口启动多个服务提供者,方便测试LoadBalancerClient的负载均衡功能,经使用消费者接口http://127.0.0.1:18710/consumer?name=hello测试发现,其默认使用**轮询**策略算法调用服务提供者。
注意:当我们关闭服务提供者,立刻调用服务消费者接口会报错:restTemplate掉接口失败,此时服务提供者实例还在本地缓存注册实例列表中,Eureka-Client 是每 30 秒定时轮询获取增量变化的注册表,从而更新本地的服务实例缓存,所以当过了30s,再次测试消费者接口,会发现获取服务提供者实例失败。