《深入理解 Spring Cloud 与微服务构建》第六章 服务注册和发现 Eureka

《深入理解 Spring Cloud 与微服务构建》第六章 服务注册和发现 Eureka

一、Eureka 简介

1.什么是 Eureka

和 Consul、Zookeeper 类似,Eureka 是一个用于服务注册和发现的组件,最开始主要应用于亚马逊公司旗下的云计算服务平台 AWS。Eureka 分为 Eureka Server 和 Eureka Client,Eureka Server 为 Eureka 服务注册中心,Eureka Client 为 Eureka 客户端

2.Eureka 的优势

  • Eureka 完全开源,经历了 Netflix 公司的生产环境的考验,以及 3 年时间的不断迭代,在功能和性能上都非常稳定,可以放心使用
  • Eureka 是 Spring Cloud 首选推荐的服务注册与发现组件,与 Spring Cloud 其它组件可以无缝对接
  • Eureka 和其它组件,比如负载均衡组件 Ribbon、熔断器组件 Hystrix、熔断器监控组件 Hystrix Dashboard 组件、熔断器聚合监控 Turbine 组件,以及网关 Zuul 组件相互配合,能够很容易实现服务注册、负载均衡、熔断和智能路由等功能。这些组件都是由 Netflix 公司开源的,一起被称为 Netflix OSS 组件。Netflix OSS 组件由 Spring Cloud 整合为 Spring Cloud Netflix 组件,它是 Spring Cloud 构架微服务的核心组件,也是基础组件

3.Eureka 的基本架构

Eureka 主要包括 3 种角色

  • Register Service:服务注册中心,它是一个 Eureka Server,提供服务注册和发现的功能
  • Provider Service:服务提供者,它是一个 Eureka Client,提供服务
  • Consumer Service:服务消费者,它是一个 Eureka Client,消费服务

服务消费的基本过程

首先需要一个服务注册中心 Eureka Server,服务提供者 Eureka Client 向服务注册中心 Eureka Server 注册,将自己的信息(比如服务名、服务的 IP 地址和端口信息等)通过 REST API 的形式提交给服务注册中心 Eureka Server。同样,服务消费者 Eureka Client 也需要向服务注册中心 Eureka Server 注册,同时服务消费者获取一份服务注册列表的信息,该列表包含了所有向服务注册中心 Eureka Server 注册的服务信息。获取服务注册列表信息之后,服务消费者就知道服务提供者的 IP 地址和端口等信息,可以通过 HTTP 远程调度来消费服务提供者的服务

二、Eureka 案例

本案例的项目结构如下:
在这里插入图片描述

1.创建主 Maven 工程

在主 Maven 的 pom 文件下,引入 eureka-server 和 eureka-client 两个 Module 工程共同所需的依赖,包括版本为 2.1.0.RELEASE 的 Spring Boot 依赖,版本为 Greenwich.RELEASE 的 Spring Cloud 依赖,指定 Java 版本为 1.8,编码为 UTF-8。主 Maven 的 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.sisyphus</groupId>
    <artifactId>Eureka</artifactId>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>eureka-server</module>
        <module>eureka-client</module>
    </modules>
    <packaging>pom</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
        <relativePath/>
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
    </properties>

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

</project>

2.编写 Eureka Server

创建一个 Moudle 工程,命名为 eureka-server,作为服务注册中心 Eureka Server 的工程,其工程目录结构如下:
在这里插入图片描述
在 eureka-server 工程的 pom 文件引入相关的依赖,包括继承了主 Maven 工程的 pom 文件,引入了 Eureka Server 的起步依赖 spring-cloud-starter-netflix-eureka-server,以及 Spring Boot 测试的起步依赖 spring-boot-starter-test。最后还引入了 Spring Boot 的 Maven 插件 spring-boot-maven-plugin,有了该插件,即可使用 Maven 插件的方式来启动 Spring Boot 工程,具体代码如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Eureka</artifactId>
        <groupId>org.sisyphus</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-server</artifactId>

    <dependencies>
        <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-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.1.0.RELEASE</version>
            </plugin>
        </plugins>
    </build>
    
</project>

在工程的配置文件 application.yml 中做程序的相关配置,首先通过 server.port 指定 Eureka Server 的端口为 8761.eureka.instance.prefer-ip-address 设置为 true,即提交 IP 信息。在默认情况下,Eureka Server 会向自己注册,这时需要配置 eureka.client.registerWithEureka 和 eureka.client.fetchRegistry 为 false,防止自己注册自己。配置文件 application.yml 的代码如下:

server:
  port: 8761

eureka:
  instance:
    #提交 IP 信息
    prefer-ip-address: true
    hostname: localhost

  client:
    #默认情况下,Eureka Server 会向自己注册,这时需要配置 register-with-eureka 和 fetch-registry 为 false,防止自己注册自己
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone:
        http://${eureka.instance.hostname}:${server.port}/eureka/

在工程的启动类 EurekaServerApplication 加上注解 @EnableEurekaServer,开启 EurekaServer 的功能。代码如下:

package com.sisyphus;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args){
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

至此,Eureka Server 的所有搭建工作已经完成。启动程序启动类 EurekaServerApplication 的 main 方法,启动程序。在浏览器上访问 Eureka Server 的主界面 http://localhost:8761,在界面上的 Instances currently registered with Eureka 这一项上没有任何注册的实例,因为没有 Eureka Client 向注册中心 Eureka Server 注册实例

在这里插入图片描述

3.编写 Eureka Client

向主 Maven 工程中创建一个新的 Module 工程,命名为 eureka-client,该工程作为 Eureka Client 向服务注册中心 Eureka server 注册。创建完 eureka-client 工程之后,在其 pom 文件中引入相关的依赖,其 pom 文件继承了主工程的 pom 文件,并且需要引入 Eureka Client 所需的依赖 spring-cloud-starter-netflix-eureka-client,引入 Web 功能的起步一阿里 spring-boot-starter-web,以及 Spring Boot 测试的起步依赖 spring-boot-starter-test,具体代码如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Eureka</artifactId>
        <groupId>org.sisyphus</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath/>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>eureka-client</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

在工程的配置文件 bootstrap.yml 做 Eureka Client 的相关配置,配置了程序名为 eureka-client,程序端口为 8762,服务注册地址为 http://localhost:8761/eureka/,代码如下:

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

server:
  port: 8762

spring:
  application:
    name: eureka-client

defaultZone 指的是 Eureka Client 的注册地址

在程序的启动类 EurekaClientApplication 加上注解 @EnableEurekaClient 开启 Eureka Client 功能,其代码如下:

package com.sisyphus;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@EnableEurekaClient
@SpringBootApplication
public class EurekaClientApplication {
    public static void main(String[] args){
        SpringApplication.run(EurekaClientApplication.class, args);
    }
}

在浏览器上打开 Eureka Server 主页 http://localhost:8761
在这里插入图片描述

在主页上的 Instances currently registered with Eureka 选项中已经有了一个实例被注册,Application 为 EUREKA-CLIENT,Status 为 UP(在线),端口为 8762,这就说明 Eureka Client 已成功向 Eureka Server 注册

在 eureka-client 工程中写一个 API 接口。新建一个类 HiController,其请求地址映射为 “/hi”,其中 @Values("${server.port}") 向配置文件读取配置的端口信息,其完整代码如下:

package com.sisyphus.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HiController {

    @Value("${server.port}")
    String port;

    @GetMapping
    public String home(@RequestParam String name){
        return "hi " + name + ", i am from port:" + port;
    }
}

在浏览器上访问 http://localhost:8762/hi?name=sisyphus,浏览器显示如下信息:

在这里插入图片描述

三、Eureka 的一些概念

1.服务注册与服务下线

服务注册(Register)

当 Eureka Client 向 Eureka Server 注册时,Eureka Client 提供自身的元数据,比如 IP 地、端口、运行状况指标的 Url、主页地址等信息

服务续约(Renew)

Eureka Client 在默认的情况下会每隔 30 秒发送一次心跳来进行服务续约。通过服务续约来告知 Eureka Server 该 Eureka Client 仍然可用,没有出现故障。在正常情况下,如果 Eureka Server 在 90 秒内没有收到 Eureka Client 的心跳,Eureka Server 会将 Eureka Client 实例从注册列表中删除

获取服务注册列表信息(Fetch Registries)

Eureka Client 从 Eureka Server 获取服务注册列表信息,并将其缓存在本地。Eureka Client 会使用服务注册列表信息查找其它服务的信息,从而进行远程调用。该注册列表信息定时(每 30 秒)更新一次,每次返回的注册列表信息可能与 Eureka Client 的缓存信息不同,Eureka Client 会自己处理这些信息。如果某种原因导致注册列表信息不能及时匹配,Eureka Client 会中心获取整个注册表信息。Eureka Server 缓存了所有的服务注册列表信息,并将整个注册列表以及每隔应用程序的信息压缩,压缩内容和没有压缩的内容完全相同。Eureka Client 和 Eureka Server 可以使用 JSON 和 XML 数据格式进行通信。在默认的情况下,Eureka Client 使用 JSON 格式的方式来获取服务注册列表的信息

服务下线(Cancel)

Eureka Client 在程序关闭时可以向 Eureka Server 发送下线请求。发送请求后,该客户端的实例信息将从 Eureka Server 的服务注册列表中删除。该下线请求不会自动完成,需要在程序关闭时调用以下代码:

DiscoveryManager.getInstance().shutdownComponent():

服务剔除(Eviction)

在默认情况下,当 Eureka Client 连续 90 秒没有向 Eureka Server 发送服务续约(即心跳)时,Eureka Server 会将该服务实例从服务注册列表删除,即服务剔除

2.Eureka 的高可用架构

在这里插入图片描述

从上图可知,在这个架构中有两个角色,即 Eureka Server 和 Eureka Client。而 Eureka Client 又分为 Application Service 和 Application Client,即服务提供者和服务消费者。每个区域有一个 Eureka 集群,并且每个区域至少有一个 Eureka Server 可以处理区域故障,以防服务器瘫痪

Eureka Client 向 Eureka Server 注册,将自己的客户端信息提交给 Eureka Server。然后,Eureka Client 通过向 Eureka Server 发送心跳(每 30 秒一次)来续约服务。如果某个客户端不能持续续约,那么 Eureka Server 断定该客户端不可用,该不可用的客户端将在大约 90 秒后从 Eureka Server 服务注册列表中删除。服务注册列表信息和服务续约信息会被复制到集群中的每个 Eureka Server 节点。来自任何区域的 Eureka Client 都可以获取整个系统的服务注册列表信息。根据这些注册列表信息,Application Client 可以远程调用 Application Service 来消费服务

3.为什么 Eureka Client 获取服务实例比较慢

Eureka Client 的注册延迟
Eureka Client 启动之后,不是立即向 Eureka 注册的,而是有一个延迟向服务端注册的时间,默认的延迟时间为 40 秒

Eureka Server 的响应缓存
Eureka Server 维护每 30 秒更新一次响应缓存,可通过更改配置 eureka.server.responseCache UpdateIntervalMs 来修改。所以即使是刚刚注册的实例,也不会立即出现在服务注册列表中

Eureka Client 的缓存
Eureka Client 保留注册表信息的缓存。该缓存每 30 秒更新一次(如前所述)。因此,Eureka Client 刷新本地缓存并发现其它新注册的实例可能需要 30 秒

LoadBalancer 的缓存
Ribbon 的负载均衡平衡器从本地的 Eureka Client 获取服务注册列表信息。Ribbon 本身还维护了缓存,以避免每个请求都需要从 Eureka Client 获取服务注册列表。此缓存每 30 秒刷新一次(可由 ribbon.ServerListRefreshInterval 配置),所以可能至少需要 30 秒的时间才能使用新注册的实例

综上因素,一个新注册的实例,默认延迟 40 秒向服务注册中心注册,所以不能马上被 Eureka Server 发现。另外,刚注册的 Eureka Client 也不能立即被其它服务调用,原因是调用方由于各种缓存没有及时获取到最新的服务注册列表信息

4.Eureka 的自我保护模式

当有一个新的 Eureka Server 出现时,它尝试从相邻 Peer 节点获取所有服务实例注册列表信息。如果从相邻的 Peer 节点获取信息时出现了故障, Eureka Server 会尝试其它的 Peer 节点。如果 Eureka Server 能够成功获取所有的服务实力信息,则根据配置信息设置服务续约的阈值。在任何时间,如果 Eureka Server 接收到的服务续约低于为该值配置的百分比(默认为 15 分钟内低于 85%),则服务器开启自我保护模式,即不再剔除注册列表的信息

这样做的好处在于,如果是 Eureka Server 自身的网络问题而导致 Eureka Client 无法续约,Eureka Client 的注册列表信息不再被删除,也就是 Eureka Client 还可以被其它服务消费

在默认情况下,Eureka Server 的自我保护模式是开启的,如果需要关闭,则在配置文件添加以下代码:

eureka:
	server:
		enable-self-preservation: false
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值