Spring Cloud 系列之注册中心 Eureka详解

 更新时间:2020年11月03日 10:56:06   作者:Demo_Null  
Netflix Eureka 是由 Netflix 开源的一款基于 REST 的服务发现组件,包括 Eureka Server 及 Eureka Client。这篇文章主要介绍了Spring Cloud 系列之注册中心 Eureka,需要的朋友可以参考下

1.1 简介

 1.1.1 概述

  Netflix Eureka 是由 Netflix 开源的一款基于 REST 的服务发现组件,包括 Eureka Server 及 Eureka Client。2012 年 9 月在 GitHub 上发布 1.1.2 版本,目前 Netflix 以宣布闭源,所以市面上还是以 1.x 版本为主。Eureka 提供基于 REST 的服务,在集群中主要用于服务管理。Eureka 提供了基于 Java 语言的客户端组件,客户端组件实现了负载均衡的功能,为业务组件的集群部署创造了条件。使用该框架,可以将业务组件注册到 Eureka 容器中,这些组件可进行集群部署,Eureka 主要维护这些服务的列表并自动检查它们的状态。Spring Cloud Netflix Eureka 是 Pivotal 公司为了将 Netflix Eureka 整合于 Spring Cloud 生态系统提供的版本。
  Eureka 包含两个组件:Eureka Server 和 Eureka Client, Eureka Server 提供服务注册服务。各个微服务节点通过配置启动后,会在 EurekaServer 中进行注册,这样 EurekaServer 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。EurekaClient 通过注册中心进行访问。它是一个 Java 客户端,用于简化 Eureka Server 的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向 Eureka Server 发送心跳(默认周期为30秒)。如果 Eureka Server 在多个心跳周期内没有接收到某个节点的心跳,EurekaServer 将会从服务注册表中把这个服务节点移除(默认90秒)

在这里插入图片描述

1.1.2 原理图

  一个简单的 Eureka 集群,需要一个 Eureka 服务器、若干个服务提供者。我们可以将业务组件注册到 Eureka 服务器中,其他客户端组件可以向服务器获取服务并且进行远程调用。Eureka:就是服务注册中心(可以是一个集群),对外暴露自己的地址;提供者:启动后向 Eureka 注册自己信息(地址,提供什么服务);消费者:向 Eureka 订阅服务,Eureka 会将对应服务的所有提供者地址列表发送给消费者,并且定期更新;心跳(续约):提供者定期通过 http 方式向 Eureka 刷新自己的状态。

在这里插入图片描述

1.1.3 相关依赖

<!-- 需要确定 Spring Cloud 版本 -->
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

1.2 搭建 EurekaServer

 1.2.1 相关依赖

  现在都是子父工程,我们将子模块中都需要用的依赖放到父工程的 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>
 <packaging>pom</packaging>
 <modules>
 <module>eureka</module>
 </modules>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>2.2.10.RELEASE</version>
 <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>com.software</groupId>
 <artifactId>spring-cloud</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>spring-cloud</name>
 <description>Demo project for Spring Boot</description>

 <properties>
 <java.version>1.8</java.version>
 <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
 </properties>

 <dependencies>
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
 </dependency>
 <!-- 演示就不使用数据库了 -->
		<!--<dependency>-->
		<!--<groupId>org.springframework.boot</groupId>-->
		<!--<artifactId>spring-boot-starter-data-jpa</artifactId>-->
		<!--</dependency>-->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <!-- H 版 Spring Cloud 将 server 与 client 分开了,需要导入两个坐标 -->
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
 </dependency>
 <dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
 </dependency>
 </dependencies>

 <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>

 <build>
 <plugins>
  <plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  </plugin>
 </plugins>
 </build>

</project>

1.2.2 声明为 Eureka Server

  在 eureka 服务的启动类上使用 @EnableEurekaServer,声明当前应用为 Eureka 服务。

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/10/29
 * @description Eureka 启动类
 */
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
 public static void main(String[] args) {
 SpringApplication.run(EurekaApplication.class, args);
 }
}

1.2.3 配置文件

server:
 port: 8081

spring:
 application:
 name: eurekaServer # 应用名称,在 Eureka 中作为 id 标识

eureka:
 client:
 register-with-eureka: false # 不注册自己
 fetch-registry: false # 不拉取自己
 service-url:
 defaultZone: http://127.0.0.1:8081/eureka/ # EurekaServer 的地址,如果是集群,需要加上其它 Server 的地址

1.2.4 启动服务

  启动服务访问对应的端口就可以看到以下界面,现在是一个服务都没有注册上来。可以把 register-with-eurekafetch-registry 两个配置取消就可以看到 eureka 自己了。

在这里插入图片描述

在这里插入图片描述




1.3 提供者

1.3.1 声明为 Eureka Client

  在服务提供者启动类中使用 @EnableDiscoveryClient,让 Eureka 能够发现,扫描到该服务。@EnableEurekaClient 注解也能实现但是该注解只支持 Eureka 作为注册中心,@EnableDiscoveryClient 可以是其他注册中心,建议使用 @EnableDiscoveryClient

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/10/29
 * @description 服务提供者启动类
 */
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
 public static void main(String[] args) {
 SpringApplication.run(ProviderApplication.class, args);
 }
}

1.3.2 配置文件

server:
 port: 8082

spring:
 application:
 name: ProviderServer # 应用名称,在 Eureka 中作为 id 标识

eureka:
 client:
 service-url:
 defaultZone: http://127.0.0.1:8081/eurake/

1.3.3 提供服务

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/10/29
 * @description
 */

@RestController
@RequestMapping("/provider")
public class ProviderController {

 @GetMapping("/get")
 public Object get() {
 return "你已经消费了";
 }
}

1.3.4 启动服务

  启动服务之后,会自动将自己注册到 Eureka 中

在这里插入图片描述

1.4 消费者

1.4.1 声明为 Eureka Client

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/10/29
 * @description 消费者启动类
 */
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
 public static void main(String[] args) {
 SpringApplication.run(ConsumerApplication.class, args);
 }
	
	// 将 RestTemplate 交由容器管理
 @Bean
 public RestTemplate getRestTemplate() {
 return new RestTemplate();
 }
}

1.4.2 配置文件

server:
 port: 8083

spring:
 application:
 name: ConsumerServer # 应用名称,在 Eureka 中作为 id 标识

eureka:
 client:
 service-url:
 defaultZone: http://127.0.0.1:8081/eureka

1.4.3 消费服务

  我们之前使用 RestTemplate 需要自己写 URI,这样很不利于维护,而且容易出错,现在只需要确定应用名称,利用应用名称从 Eureka 中就可以获取到详细信息。

/**
 * Created with IntelliJ IDEA.
 *
 * @author gaohu9712@163.com
 * @date 2020/10/29
 * @description
 */
@RestController
@RequestMapping("/consumer")
public class ConsumerController {

 @Autowired
 private DiscoveryClient discoveryClient;


 @GetMapping("/go")
 public void go() {
 List<ServiceInstance> providerServer = discoveryClient.getInstances("ProviderServer");

 if (0 == providerServer.size()) {
  return;
 }

 ServiceInstance serviceInstance = providerServer.get(0);
 String host = serviceInstance.getHost();
 int port = serviceInstance.getPort();
 URI uri = serviceInstance.getUri();
 System.out.println("主机:" + host);
 System.out.println("端口:" + port);
 System.out.println("uri:" + uri);

 RestTemplate restTemplate = new RestTemplate();
 String str = restTemplate.getForObject(uri + "/provider/get", String.class);
 System.out.println(str);
 }
}

1.4.4 启动服务

在这里插入图片描述

1.4.5 请求服务

在这里插入图片描述

1.4.6 执行流程

 ♞ 先启动 eureka 注册中心
 ♞ 启动服务提供者 provider
 ♞ 服务提供者启动后会把自身信息(比如服务地址以别名方式注册进 eureka)
 ♞ 消费者 consumer 服务在需要调用接口时,使用服务别名去注册中心获取实际的 RPC 远程调用地址
 ♞ 消费者获得调用地址后,底层实际是利用 HttpClient 技术实现远程调用
 ♞ 消费者获得服务地址后会缓存在本地 jvm 内存中,默认每间隔 30 秒更新一次服务调用地址

1.5 补充配置

1.5.1 actuator 信息完善

  我们现在的服务注册到 Eureka 上面是没有 ip 地址的,以后等服务搭建集群是很不方便的,所以我们需要让他显示自己的 ip 地址;第二个就是服务名称为主机 + 服务名 + 端口,这样就暴露了主机名,我们可以指定显示的名称。

在这里插入图片描述

在配置文件中添加如下配置,通过健康检查(http://ip:port/actuator/health)查看是否修改成功。

eureka:
 instance:
 # 实例名称
 instance-id: consumer-01
 # 地址中显示 ip 
 prefer-ip-address: true

在这里插入图片描述

1.5.2 自我保护机制 ☞ 概述

  我们可以看到 Eureka 上有一行红色的英文 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 Server 将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
  默认情况下,如果 Eureka Server 在一定时间内没有接收到某个微服务实例的心跳,Eureka Server 将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与 Eureka Server 之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。为了防止 Eureka Client 可以正常运行,但是与 Eureka Server 网络不通情况下,Eureka Server 不会立刻将 Eureka Client 服务剔除。

☞ 关闭自我保护机制

  我们之前的 Eureka 截图中可以看到 DESKTOP-GL7GS52:ConsumerServer:8083consumer-01 两个同时存在,这明明是一个服务,修改完配置之后前面的没有剔除,这就是因为自我保护机制打开了。

# Eureka Server 配置
eureka:
 server:
 # 关闭自我保护模式, 默认为打开
 enable-self-preservation: false 
 # 续期时间,即扫描失效服务的间隔时间 
 eviction-interval-timer-in-ms: 5000 


# Eureka Client 配置
eureka:
 instance:
 # Eureka Client 给 Eureka Server 发送心跳的时间间隔,默认 30 单位是 s
 lease-renewal-interval-in-seconds: 1
 # Eureka Server 最后一次收到心跳的等待上限,超时剔除服务,默认 90 单位是 s
 lease-expiration-duration-in-seconds: 2

1.6 Eureka 高可用

1.6.1 Eureka 集群搭建

  在之前的单体中我们的端口是随意的,但是搭建集群我们需要对端口进行规划,例如将 808X 端口作为 Eureka 集群的端口。先来看下配置有什么区别,起初我们是将自己注册到自己上,现在我们需要将自己注册到其他 Eureka 上,有多个则用 , 隔开。

server:
 port: 8081

spring:
 application:
 name: eurekaServer

eureka:
 client:
 register-with-eureka: false
 fetch-registry: false
 service-url:
 defaultZone: http://127.0.0.1:8082/eureka
 server:
 enable-self-preservation: false
 eviction-interval-timer-in-ms: 5000
server:
 port: 8082

spring:
 application:
 name: eurekaServer_back

eureka:
 client:
 register-with-eureka: false
 fetch-registry: false
 service-url:
 defaultZone: http://127.0.0.1:8081/eureka
 server:
 enable-self-preservation: false
 eviction-interval-timer-in-ms: 5000

在这里插入图片描述
在这里插入图片描述

1.6.2 Privoder 集群

  服务提供者的集群配置了多个 Eureka 地址,会将自己同时注册到多个 Eureka 上,除了配置文件以外其他的服务代码完全一致,也可以加以区分是哪个提供的服务。需要注意的是 Eureka 集群的应用名称可以不一致甚至不写,但是服务提供者的应用名称必须保持一致,否则会被认为不是一个服务。

server:
 port: 8091

spring:
 application:
 name: ProviderServer # 应用名称,在 Eureka 中作为 id 标识

eureka:
 client:
 service-url:
 defaultZone: http://127.0.0.1:8081/eureka, http://127.0.0.1:8082/eureka
 instance:
 instance-id: provider-prim
 prefer-ip-address: true
 lease-renewal-interval-in-seconds: 1
 lease-expiration-duration-in-seconds: 2
server:
 port: 8092

spring:
 application:
 name: ProviderServer

eureka:
 client:
 service-url:
 defaultZone: http://127.0.0.1:8081/eureka, http://127.0.0.1:8082/eureka
 instance:
 instance-id: provider-back
 prefer-ip-address: true
 lease-renewal-interval-in-seconds: 1
 lease-expiration-duration-in-seconds: 2

在这里插入图片描述

1.6.3 远程调用

/**
 * Created with IntelliJ IDEA.
 *
 * @author Demo_Null
 * @date 2020/10/29
 * @description
 */
@RestController
@RequestMapping("/consumer")
public class ConsumerController {

 @Autowired
 private DiscoveryClient discoveryClient;


 @GetMapping("/go")
 public void go() {
 List<ServiceInstance> providerServer = discoveryClient.getInstances("ProviderServer");

 if (0 == providerServer.size()) {
  return;
 }

 RestTemplate restTemplate = new RestTemplate();

 for (ServiceInstance instance : providerServer) {
  System.out.print(instance.getUri() + "---");
  String url = instance.getUri() + "/provider/get";
  System.out.println(restTemplate.getForObject(url, String.class));
 }
 }
}

在这里插入图片描述

  咱们可以使用服务发现 DiscoveryClient 来获取服务信息,但是无法自动选择使用那个服务,这里就涉及到 Ribbon 负载均衡了。我们可以将 RestTemplate 交由 Ioc 管理,在注入时使用 @LoadBalanced 注解进行负载均衡。

☞ 源码

到此这篇关于Spring Cloud 系列之注册中心 Eureka的文章就介绍到这了,更多相关Spring Cloud 注册中心Eureka内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java函数式编程(十二):监控文件修改

    Java函数式编程(十二):监控文件修改

    这篇文章主要介绍了Java函数式编程(十二):监控文件修改,本文是系列文章的第12篇,其它文章请参阅本文底部的相关文章,需要的朋友可以参考下
    2014-09-09
  • SpringBoot实现文件上传与下载功能的示例代码

    SpringBoot实现文件上传与下载功能的示例代码

    文件上传与下载是Web应用开发中常用的功能之一。接下来我们将讨论如何在Spring Boot的Web应用开发中,如何实现文件的上传与下载,感兴趣的可以了解一下
    2022-06-06
  • 如何在IDEA中查看依赖关系的方法步骤

    如何在IDEA中查看依赖关系的方法步骤

    这篇文章主要介绍了如何在IDEA中查看依赖关系的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • 关于Java项目读取resources资源文件路径的那点事

    关于Java项目读取resources资源文件路径的那点事

    这篇文章主要介绍了关于Java项目读取resources资源文件路径的那点事,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 详解HTTP请求与响应基础及实例

    详解HTTP请求与响应基础及实例

    这篇文章主要介绍了详解HTTP请求与响应基础及实例的相关资料,这里对http的请求和响应进行详细分析并附有实现实例,需要的朋友可以参考下
    2017-07-07
  • SpringBoot之瘦身部署的详细步骤

    SpringBoot之瘦身部署的详细步骤

    本篇文章主要介绍了SpringBoot之瘦身部署的详细步骤,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Java静态代理与动态代理案例详解

    Java静态代理与动态代理案例详解

    这篇文章主要介绍了Java静态代理与动态代理案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • 详解Mybatis分页插件 - 示例代码

    详解Mybatis分页插件 - 示例代码

    这篇文章主要介绍了详解Mybatis分页插件 - 示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧。
    2016-12-12
  • 深入理解Java new String()方法

    深入理解Java new String()方法

    今天给大家带来的是关于Java的相关知识,文章围绕着Java new String()展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • 简单学习Java+MongoDB

    简单学习Java+MongoDB

    本文给大家介绍的是如何简单的使用java+MongoDB实现数据调用的问题,非常的实用,有需要的小伙伴可以参考下
    2016-03-03

最新评论