Eureka

Spring Cloud服务注册与发现组件。

注:SpringCloud可以说是一种微服务规范。

第一代实现:Spring Cloud Netfilx

第二代实现:Spring Cloud Alibaba

这里的SpringCloud特指SpringCloud的第一代实现。

  • Spring Cloud将Eureka与Netflix中的其他组件一起整合进Spring Cloud Netflix模块中,整合后的组件全称为Spring Cloud Netflix Eureka。
  • Spring Cloud使用SpringBoot思想为Eureka增加了自动化配置,开发人员只需要引入相关依赖和注解。

Eureka两大组件

Eureka采用CS架构

  • Eureka Server:Eureka服务注册中心,主要提供服务注册功能。微服务启动后,会将自己的服务注册到Eureka Server。Eureka Server维护了一个可用服务列表,存储了所有注册到Eureka Server中的可用服务的信息。
  • Eureka Client:Eureka客户端。通常指的是微服务系统中的各个微服务。主要用于和Eureka Server进行交互。在微服务应用启动后,Eureka Client会向Eureka Server发送心跳。若Eureka Server在多个心跳周期内没有接收到某个Eureka的心跳,Eureka Server将它从可用服务列表中移除。

心跳指的是一段时间定时发送的自定义信息,让对方知道自己“存活”,以确保连接的有效性。

Eureka服务注册与发现

  • 服务注册中心:也就是Eureka Server,用于提供服务注册和发现功能。
  • 服务提供者:Eureka Client,用于提供服务。它将自己提供的服务注册到服务注册中心,以供服务消费者发现。
  • 服务消费者:Eureka Client,用于消费服务。从服务注册中心获取服务列表,调用所需要的服务。

流程:

  1. 搭建一个Eureka Server作为服务注册中心。
  2. 服务提供者启动时,会把当前服务器的信息以服务名(spring.application.name)的方式注册到服务注册中心。
  3. 服务消费者启动时,也会向服务注册中心注册。
  4. 服务消费者会获取一份可用服务列表,该列表包含了所有注册到服务注册中心的服务信息。(服务提供者包括自身)
  5. 在获得了可用服务列表后,服务消费者通过HTTP或消息中间件远程调用服务提供者提供的服务。

注:服务注册中心是服务提供者和服务消费者之间的桥梁。服务提供者只有将自己的服务注册到服务注册中心才有可能被服务消费者调用,而服务消费者也只有通过服务注册中心获取可用服务列表后,才能调用所需的服务。

1.创建主工程

本案例涉及多个Springboot创建的微服务,为了方便管理,采用Maven的多Module结构来构建工程。

创建一个名为spring-cloud-demo2的Maven主工程,然后该主工程的pom.xml中使用dependencyManagement来管理Spring Cloud的版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 <?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>
<packaging>pom</packaging>
<modules>
<module>micro-service-cloud-api</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.jiang</groupId>
<artifactId>spring-cloud-demo2</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>

<dependencyManagement>
<dependencies>
<!--在主工程中使用 dependencyManagement 声明 Spring Cloud 的版本,
这样工程内的 Module 中引入 Spring Cloud 组件依赖时,就不必在声明组件的版本信息
保证 Spring Cloud 各个组件一致性-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>microservicecloud</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
</project>

2.创建公共子模块

公共子模块包含了一些其他子模块共有的内容,例如实体类、公共工具类、公共依赖项等。当其他子模块需要使用公共子模块的内容时,只需要在其pom.xml引入公共子模块的依赖即可。

  1. 在主工程下,创建一个名为micro-service-cloud-api的Maven Module:micro-service-cloud-api 。其pom.xml配置如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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>spring-cloud-demo2</artifactId>
<groupId>com.jiang</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>micro-service-cloud-api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
  1. 在micro-service-cloud-api的com.jiang.entity包下,创建一个名为Dept的实体类,代码如下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.jiang.entity;

import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@NoArgsConstructor //无参构造函数
@Data // 提供类的get、set、equals、hashCode、canEqual、toString 方法
@Accessors(chain = true)
public class Dept implements Serializable {
private Integer deptNo;
private String deptName;
private String dbSource;
}

3.搭建服务注册中心

  1. 在主工程下创建一个名为micro-service-cloud-eureka-7001的Spring Boot Module作为服务注册中心,并在其pom.xml中引入以下依赖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    <?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>
    <!--继承主工程的 POM-->
    <parent>
    <artifactId>spring-cloud-demo2</artifactId>
    <groupId>com.jiang</groupId>
    <version>0.0.1-SNAPSHOT</version>
    </parent>
    <groupId>com.jiang</groupId>
    <artifactId>micro-service-cloud-eureka-7001</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>micro-service-cloud-eureka-7001</name>
    <description>Demo project for Spring Boot</description>

    <properties>
    <java.version>1.8</java.version>
    </properties>

    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--为服务注册中心引入 Eureka Server 的依赖-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <!--devtools 和 lombok 均为开发辅助模块,根据需求适当选择-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
    </dependency>
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </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>
    <configuration>
    <excludes>
    <exclude>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </exclude>
    </excludes>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>
  2. 在类路径下,添加一个配置文件application.yml,配置内容如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    server:
    port: 7001 #该Module的端口

    eureka:
    instance:
    hostname: localhost #eureka服务端的实例名称

    client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
    defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机版服务注册中心
  3. micro-service-cloud-eureka-7001的主启动类上使用@EnableEurekaServer注解开启服务注册中心功能,接受其他服务的注册。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
    @SpringBootApplication
    @EnableEurekaServer //开启 Eureka server,接受其他微服务的注册
    public class MicroServiceCloudEureka7001Application {
    public static void main(String[] args) {
    SpringApplication.run(MicroServiceCloudEureka7001Application.class, args);
    }
    }
  1. 启动micro-service-cloud-eureka-7001,使用浏览器访问Eureaka服务注册中心主页。地址为“http://localhost:7001/”。

4.搭建服务提供者

  1. 在主工程下创建一个名为micro-service-cloud-provider-dept-8001的Spring Boot Module,并在其pom.xml中添加依赖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    <?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>
    <!--引入父工程pom-->
    <parent>
    <artifactId>spring-cloud-demo2</artifactId>
    <groupId>com.jiang</groupId>
    <version>0.0.1-SNAPSHOT</version>
    </parent>

    <groupId>com.jiang</groupId>
    <artifactId>micro-service-cloud-provider-dept-8001</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>micro-service-cloud-provider-dept-8001</name>
    <description>Demo project for Spring Boot</description>

    <properties>
    <java.version>1.8</java.version>
    </properties>
    <dependencies>
    <!--Spring Boot Web-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--devtools 开发工具-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
    </dependency>
    <!--Spring Boot 测试-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    <!--引入公共子模块-->
    <dependency>
    <groupId>com.jiang</groupId>
    <artifactId>micro-service-cloud-api</artifactId>
    <version>${project.version}</version>
    </dependency>
    <!--junit 测试-->
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    </dependency>
    <!--mysql 驱动-->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
    </dependency>
    <!--logback 日志-->
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    </dependency>
    <!--整合 mybatis -->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
    </dependency>
    <!-- 修改后立即生效,热部署 -->
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>springloaded</artifactId>
    <version>1.2.8.RELEASE</version>
    </dependency>
    <!--引入 Eureka Client 的依赖,将服务注册到 Eureka Server-->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- Spring Boot 监控模块-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <!--mybatis自动生成代码插件-->
    <plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.4.0</version>
    <configuration>
    <configurationFile>src/main/resources/mybatis-generator/generatorConfig.xml</configurationFile>
    <verbose>true</verbose>
    <!-- 是否覆盖,true表示会替换生成的JAVA文件,false则不覆盖 -->
    <overwrite>true</overwrite>
    </configuration>
    <dependencies>
    <!--mysql驱动包-->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
    </dependency>
    <dependency>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-core</artifactId>
    <version>1.4.0</version>
    </dependency>
    </dependencies>
    </plugin>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    </plugin>
    </plugins>
    </build>
    </project>
  2. 类路径下添加application.yml配置文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    server: 
    port: 8001 #服务端口号
    spring:
    application:
    name: microServiceCloudProviderDept #微服务名称

    datasource:
    username: root
    password: root
    url: jdbc:mysql://127.0.0.1:3306/xxx
    driver-class-name: com.mysql.jdbc.Driver

    ############################### 不检查 spring.config.import=configserver:##################
    cloud:
    config:
    enabled: false

    mybatis:
    mapper-locations: classpath:mybatis/mapper/*.xml
    #扫描实体类的位置,在此处指明扫描实体类的包,在 mapper.xml 中就可以不写实体类的全路径名
    type-aliases-package: com.jiang.entity
    configuration:
    map-underscore-to-camel-case: true

    ##############################Spring cloud 自定义服务名称和 ip 地址#####################
    eureka:
    client: #将客户端注册到eureka服务列表中
    service-url:
    defaultZone: http://eureka7001.com:7001/eureka #这个地址是 7001注册中心在 application.yml 中暴露出来额注册地址
    instance:
    instance-id: spring-cloud-provider-8001 #自定义服务名称信息
    prefer-ip-address: true #显示访问路径的ip地址


    ########################################## spring cloud 使用 Spring Boot actuator 监控完善信息###################################
    # Spring Boot 2.50对 actuator 监控屏蔽了大多数的节点,只暴露了 heath 节点,本段配置(*)就是为了开启所有的节点
    management:
    endpoints:
    web:
    exposure:
    include: "*" # * 在yaml 文件属于关键字,所以需要加引号
    info:
    app.name: micro-service-cloud-provider-dept
    company.name: com.jiang
    build.aetifactId: @project.artifactId@
    build.version: @project.version@
  3. 创建一系列mapper和service层的文件。

  4. 在该主启动类中添加注解@EnableEurekaClient开启Eureka客户端功能,将服务注册到服务注册中心。

    1
    2
    3
    4
    5
    6
    7
    8
    @SpringBootApplication
    @EnableEurekaClient // Spring cloud Eureka 客户端,自动将本服务注册到 Eureka Server 注册中心中
    public class MicroServiceCloudProviderDept8001Application {

    public static void main(String[] args) {
    SpringApplication.run(MicroServiceCloudProviderDept8001Application.class, args);
    }
    }
  5. 依次启动 micro-service-cloud-eureka-7001 和 micro-service-cloud-provider-dept-8001,使用浏览器访再次问 Eureka 服务注册中心主页(http://localhost:7001/)

Eureka Server 集群

在微服务架构中,一个系统往往又十几个甚至几十个服务组成,若都注册到同一个Eureka Server 中,就可能导致Eureka Server不堪负重而崩溃,最终导致整个系统瘫痪。解决这个问题的办法就是建立Eureka Server集群。

在Eureka服务注册与发现中一共设计3个角色:服务注册中心、服务提供者和服务消费者。所有的服务都既是服务消费者也是服务提供者,服务注册中心Eureka Server也不例外。

搭建服务注册中心的配置

1
2
3
4
eureka:
client:
register-with-eureka: false #false 表示不向注册中心注册自己。
fetch-registry: false #false表示自己端就是注册中心,职责就是维护服务实例,并不需要去检索服务

这样设置的原因是micro-service-cloud-eureka-7001本身自己就是服务注册中心,不能将自己注册到自身上,但服务注册中心是可以将自己作为服务向其他的服务注册中心注册。

这样就可以形成一组相互注册的Eureka Server集群。当服务提供者发送注册请求到Eureka Server时,Eureka Server会将请求转发给集群中所有与之相连的Eureka Server中,以实现集群间的服务同步。

通过服务同步,服务消费者可以在集群中的任何一台Eureka Server上获取服务提供者提供的服务。这样其中某一个服务注册中心发生故障,服务消费者仍可以从集群中的其他Eureka Server中获取服务信息并调用,而不会直接导致整体的瘫痪。这就是集群的高可用性。