【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
应用型负载均衡 ALB,每月750个小时 15LCU
简介: 【Springcloud Alibaba微服务分布式架构 | Spring Cloud】之学习笔记(三)Eureka服务注册中心

1、服务注册与发现

当服务很多时,单靠代码手动管理是很麻烦的,需要一个公共组件,统一管理多服务,包括服务是否正常运行等

上面只有两个微服务,通过 RestTemplate ,是可以相互调用的,但是当微服务项目的数量增大,就需要服务注册中心。目前没有学习服务调用相关技术,使用 SpringCloud 自带的 RestTemplate 来实现RPC。

1.1 什么是服务治理:

SpringCloud封装了Netflix公司开发的Eureka模块来实现服务治理

在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务于服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

1.2 什么是服务注册与发现:

Eureka采用了CS的设计结构,Eureka Server服务注册功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。这点和zookeeper很相似

在服务注册与发现中,有一个注册中心。当服务器启动时候,会把当前自己服务器的信息 比如服务地址 通讯地址等以别名方式注册到注册中心上。另一方(消费者服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用。RPC远程调用框架核心设计思想:在于注册中心,因为便用注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))

1.3 Eureka服务注册与发现

Eureka 官方停更不停用,以后可能用的越来越少。

Eureka 是 Netflix 开发的,一个基于 REST 服务的,服务注册与发现的组件,以实现中间层服务器的负载平衡和故障转移。

Eureka 分为 Eureka Server 和 Eureka Client及服务端和客户端。Eureka Server为注册中心,是服务端,而服务提供者和消费者即为客户端,消费者也可以是服务者,服务者也可以是消费者。同时Eureka Server在启动时默认会注册自己,成为一个服务,所以Eureka Server也是一个客户端,这是搭建Eureka集群的基础。

==Eureka Client:==一个Java客户端,用于简化与 Eureka Server 的交互(通常就是微服务中的客户端和服务端)。通过注册中心进行访问。是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(roundrobin)负载算氵去的负载均衡器

在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)

==Eureka Server:==提供服务注册服务,各个微服务节,通过配置启动后,会在Eureka Serverc中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点信息,服务节点的信息可以在界面中直观看到。

服务在Eureka上注册,然后每隔30秒发送心跳来更新它们的租约。如果客户端不能多次续订租约,那么它将在大约90秒内从服务器注册表中剔除。注册信息和更新被复制到集群中的所有eureka节点。来自任何区域的客户端都可以查找注册表信息(每30秒发生一次)来定位它们的服务(可能在任何区域)并进行远程调用。

服务提供者向注册中心注册服务,并每隔30秒发送一次心跳,就如同人还活着存在的信号一样,如果Eureka在90秒后还未收到服务提供者发来的心跳时,那么它就会认定该服务已经死亡就会注销这个服务。这里注销并不是立即注销,而是会在60秒以后对在这个之间段内“死亡”的服务集中注销,如果立即注销,势必会对Eureka造成极大的负担。这些时间参数都可以人为配置。

Eureka还有自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,所以不会再接收心跳,也不会删除服务。

客户端消费者会向注册中心拉取服务列表,因为一个服务器的承载量是有限的,所以同一个服务会部署在多个服务器上,每个服务器上的服务都会去注册中心注册服务,他们会有相同的服务名称但有不同的实例id,所以拉取的是服务列表。我们最终通过负载均衡来获取一个服务,这样可以均衡各个服务器上的服务。

2、单机版eureka

  • 消费者端口80,提供者端口8001。
  • Eureka端口7001

2.1 创建module

Cloud_eureka_server_7001

2.2改pom依赖

eureka版本说明:

<!--新版本2020.02-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--旧版本2018-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

pom文件:

在这里插入代码片

2.3写yml配置文件:

server:
  port: 7001
eureka:
  instance:
    hostname: localhost  # eureka 服务端的实例名称
  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与 Eureka Server 交互的地址,查询服务 和 注册服务都依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2.4主启动类

@EnableEurekaServer

最后写主启动类,如果启动报错,说没有配置 DataSource ,就在 主启动类的注解加上 这样的配置:

package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7001 {
    public static void main(String[] args){
        SpringApplication.run(EurekaServerMain7001.class, args);
        log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");
    }
}

启动测试,访问 7001 端口

2.5 修改服务提供者 cloud-provider-payment8001 模块,

  1. 在 pom 文件的基础上引入 eureka 的client包,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">
    <parent>
        <artifactId>springcloud2023</artifactId>
        <groupId>com.tigerhhzz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Cloud-provider-payment8001</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 服务注册中心的客户端端 eureka-client -->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.tigerhhzz.springcloud</groupId>
            <artifactId>Cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <!--这个和web要写到一块-->
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </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>
</project>
  1. 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import java.io.Console;
/**
 * @author Administrator
 */
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {
    public static void main(String[] args){
        SpringApplication.run(PaymentMain8001.class, args);
        log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");
    }
}
  1. yml 文件添加关于 Eureka 的配置:
server:
  port: 8001
spring:
  application:
    name: Cloud-provider-payment8001
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
      defaultZone: http://localhost:7001/eureka/

2.6 修改消费者 cloud-customer-order80 模块

  1. 在 pom 文件的基础上引入 eureka 的client包,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">
    <parent>
        <artifactId>springcloud2023</artifactId>
        <groupId>com.tigerhhzz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Cloud-consumer-order80</artifactId>
    <dependencies>
        <!-- 服务注册中心的客户端端 eureka-client -->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.tigerhhzz.springcloud</groupId>
            <artifactId>Cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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>
</project>
  1. 主启动类 加上注解 :@EnableEurekaClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80{
    public static void main(String[] args){
        SpringApplication.run(OrderMain80.class,args);
        log.info("OrderMain80启动成功~~~~~~~~~~~~~~~~~~~");
    }
}
  1. yml 文件添加关于 Eureka 的配置:
server:
  port: 80
spring:
  application:
    name: Cloud-consumer-order80
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka/

2.7 启动三个服务:

3、集群版eureka

3.1 集群原理

  1. 就是pay模块启动时,注册自己,并且自身信息也放入eureka
  2. order模块,首先也注册自己,放入信息,当要调用pay时,先从eureka拿到pay的调用地址
  3. 通过HttpClient调用 ,并且还会缓存一份到本地,每30秒更新一次

问题:微服务RPC远程服务调用最核心的是什么:

高可用,试想你的注册中心只有一个。onlyone,它出故障了那就呵呵了,会导致整个为服务环境不可用,所以要搭建Eureka注册中心集群,实现负载均衡+故障容错

Eureka 集群的原理:

== 相互注册,互相守望。== 每台Eureka服务器都有集群里其他Eureka服务器地址的信息

3.2 构建Eureka集群

在写配置文件前,修改一下主机的hosts文件

模拟多个 为了不用输出C:\Windows\System32\drivers\etc\hosts 添加如下:
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
  1. 创建 Cloud-eureka-server7002模块
    这也就是第二个 Eureka 服务注册中心,pom 文件和 主启动类,与第一个Cloud-eureka-server7002一致。
pom文件:
  粘贴7001的即可
<?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>springcloud2023</artifactId>
        <groupId>com.tigerhhzz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Cloud-eureka-server7002</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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.tigerhhzz.springcloud</groupId>
            <artifactId>Cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>
配置文件:
  1. 修改7001项目的application.yml配置文件

首先修改之前的7001的eureka项目,因为多个eureka需要互相注册

7001项目的application.yml配置文件

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com  # eureka 服务器的实例地址  # eureka 服务端的实例名称
  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      ## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
      defaultZone: http://eureka7002.com:7002/eureka/
  1. 修改7002项目的application.yml配置文件
7002也是一样的,只不过端口和地址改一下

7002项目的application.yml配置文件

server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com  # eureka 服务端的实例名称
  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      ## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
      defaultZone: http://eureka7001.com:7001/eureka/

eureka.instance.hostname 才是启动以后 本 Server 的注册地址,而 service-url 是 map 类型,只要保证 key:value 格式就行,它代表 本Server 指向了那些 其它Server 。利用这个,就可以实现Eureka Server 相互之间的注册,从而实现集群的搭建。

  1. 主启动类:

复制7001的即可

7001主启动类:

package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7001 {
    public static void main(String[] args){
        SpringApplication.run(EurekaServerMain7001.class, args);
        log.info("EurekaServerMain7001启动成功~~~~~~~~~~~~~~~~~~~");
    }
}

7002主启动类:

package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@Slf4j
// exclude :启动时不启用 DataSource的自动配置检查
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableEurekaServer   // 表示它是服务注册中心
public class EurekaServerMain7002 {
    public static void main(String[] args){
        SpringApplication.run(EurekaServerMain7002.class, args);
        log.info("EurekaServerMain7002启动成功~~~~~~~~~~~~~~~~~~~");
    }
}
  1. 然后启动7001,7002即可

3.3 将Cloud-consumer-order80,Cloud-provider-payment8001模块注册到eureka集群中

  1. 只需要修改Cloud-consumer-order80,Cloud-provider-payment8001模块的配置文件即可:

Cloud-consumer-order80配置文件

server:
  port: 80
spring:
  application:
    name: Cloud-consumer-order80
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
#      defaultZone: http://localhost:7001/eureka/   #单机版
      defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/   #集群版

,Cloud-provider-payment8001模块配置文件

server:
  port: 8001
spring:
  application:
    name: Cloud-provider-payment8001
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
  1. 两个模块都修改上面的都一样即可

然后启动两个模块

要先启动7001,7002,然后是pay模块8001,然后是order(80)

4、将Cloud-provider-payment模块也配置为集群模式

4.1 创建新模块Cloud-provider-payment8002

4.2 pom文件,复制8001的

Cloud-provider-payment8002模块的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">
    <parent>
        <artifactId>springcloud2023</artifactId>
        <groupId>com.tigerhhzz.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Cloud-provider-payment8002</artifactId>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- 服务注册中心的客户端端 eureka-client -->
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包 -->
        <dependency>
            <groupId>com.tigerhhzz.springcloud</groupId>
            <artifactId>Cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <!--这个和web要写到一块-->
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.8</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </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>
</project>

4.3 配置文件复制8001的

端口修改一下,改为8002

Cloud-provider-payment8001模块的配置文件

server:
  port: 8001
spring:
  application:
#    name: Cloud-provider-payment8001
     name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版

Cloud-provider-payment8002模块的配置文件

server:
  port: 8002
spring:
  application:
#    name: Cloud-provider-payment8002
    name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版

服务名称不用改,用一样的

4.4 主启动类,复制8001的

package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
 * @author Administrator
 */
@Slf4j
@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8002 {
    public static void main(String[] args){
        SpringApplication.run(PaymentMain8002.class, args);
        log.info("PaymentMain8002启动成功~~~~~~~~~~~~~~~~~~~");
    }
}

4.5 mapper,service,controller都复制一份

然后就启动服务即可

此时访问order模块,发现并没有负载均衡到两个pay,模块中,而是只访问8001

虽然我们是使用RestTemplate访问的微服务,但是也可以负载均衡的

4.6 RestTemplate开启负载均衡注解

注意这样还不可以,需要让RestTemplate开启负载均衡注解,还可以指定负载均衡算法,默认轮询

修改Cloud-consumer-order80模块中的config包下面的ApplicationContextConfig类:

package com.tigerhhzz.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
 * @author tigerhhzz
 * @date 2023/4/8 22:52
 */
@Configuration
public class ApplicationContextConfig {
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
        /*
        RestTemplate提供了多种便捷访问远程http服务的方法,
        是一种简单便捷的访问restful服务模板类,是spring提供的用于rest服务的客户端模板工具集
        */
    }
}

4.7 修改服务主机名和ip在eureka的web上显示

actuator让Eureka显示ip

为了在微服务Eureka控制台能看到我们的某个具体服务是在哪台服务器上部署的,我们需要配置一些内容。

修改 提供者在Eureka 注册中心显示的 主机名:即修改eureka:instance:instance-id:和eureka:instance:prefer-ip-address:

修改Cloud-provider-payment8001模块的配置文件:

server:
  port: 8001
spring:
  application:
#    name: Cloud-provider-payment8001
     name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
       
  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 访问路径可以显示ip地址

修改Cloud-provider-payment8002模块的配置文件:

server:
  port: 8002
spring:
  application:
#    name: Cloud-provider-payment8002
    name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
       
  instance: #重点,和client平行
    instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 访问路径可以显示ip地址

5、eureka服务发现

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息。(即我们前面可视化页面的信息)

5.1 首先添加一个注解,在controller中

package com.tigerhhzz.springcloud.controller;
import com.tigerhhzz.springcloud.entities.CommonResult;
import com.tigerhhzz.springcloud.entities.Payment;
import com.tigerhhzz.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController   //必须是这个注解,因为是模拟前后端分离的restful风格的请求,要求每个方法返回 json
@Slf4j
public class PaymentController {
  @Resource
  private PaymentService paymentService;
    //服务发现
    @Resource
    private DiscoveryClient discoveryClient;
    @Value("${server.port}")
    private String serverPort;
  @PostMapping(value = "/payment/create")
  //      注意这里的 @RequestBody  是必须要写的,虽然 MVC可以自动封装参数成为对象,
  //      但是当消费者项目调用,它传参是 payment 整个实例对象传过来的, 即Json数据,因此需要写这个注解
  //
  public CommonResult create(@RequestBody Payment payment){
      int result = paymentService.create(payment);
      log.info("****插入结果:" + result);
      if(result > 0){
          return new CommonResult(200, "插入数据库成功", result);
      }
      return new CommonResult(400, "插入数据库失败", null);
  }
  @GetMapping(value = "/payment/{id}")
  public CommonResult getPaymentById(@PathVariable("id")Long id){
      Payment result = paymentService.getPaymentById(id);
      log.info("****查询结果:" + result);
      if(result != null){
          return new CommonResult(200, "查询成功", result);
      }
      return new CommonResult(400, "没有对应id的记录", null);
  }
    @GetMapping("queryAllByLimit")
    public CommonResult<List<Payment>> queryAllByLimit(@RequestParam(defaultValue = "0") int offset,
                                                       @RequestParam(defaultValue = "10") int limit) {
        List<Payment> payment = this.paymentService.queryAllByLimit(offset, limit);
        return new CommonResult<>(200, "select success, serverPort:" + serverPort, payment);
    }
    @GetMapping("/customer/discovery")
    public Object discovery(){
        //获得服务清单列表
        List<String> services = discoveryClient.getServices();
        for(String service: services){
            log.info("*****service: " + service);
        }
        // 根据具体服务进一步获得该微服务的信息
        List<ServiceInstance> instances = discoveryClient.getInstances("cloud-provider-service");
        for(ServiceInstance serviceInstance:instances){
            log.info(serviceInstance.getServiceId() + "\t" + serviceInstance.getHost()
                    + "\t" + serviceInstance.getPort() + "\t" + serviceInstance.getUri());
        }
        return this.discoveryClient;
    }
}

5.2 在主启动类上添加一个注解

  • 在主启动类上添加注解:@EnableDiscoveryClient
package com.tigerhhzz.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import java.io.Console;
/**
 * @author Administrator
 */
@Slf4j
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {
    public static void main(String[] args){
        SpringApplication.run(PaymentMain8001.class, args);
        log.info("PaymentMain8001启动成功~~~~~~~~~~~~~~~~~~~");
    }
}

打印输出:

6、Eureka自我保护

综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

禁止自我保护:(如果想)

6.1 在 Eureka Server 的模块中的 yml 文件进行配置:

Cloud-eureka-server7001配置文件:

server:
  port: 7001
eureka:
  instance:
    hostname: eureka7001.com  # eureka 服务器的实例地址  # eureka 服务端的实例名称
  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      ## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
      defaultZone: http://eureka7002.com:7002/eureka/
  server: # 与client平行
    # 关闭自我保护机制,保证不可用该服务被及时剔除
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 2000

Cloud-eureka-server7002配置文件:

server:
  port: 7002
eureka:
  instance:
    hostname: eureka7002.com  # eureka 服务端的实例名称
  client:
    # false 代表不向服务注册中心注册自己,因为它本身就是服务中心
    register-with-eureka: false
    # false 代表自己就是服务注册中心,自己的作用就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      ## 一定要注意这里的地址,这是搭建集群的关键。反过来写,写的是集群中其他Eureka服务器的地址
      defaultZone: http://eureka7001.com:7001/eureka/
  server: # 与client平行
    # 关闭自我保护机制,保证不可用该服务被及时剔除
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 2000

6.2 服务提供者配置

修改 Eureka Client —Cloud-provider-payment8001模块的 心跳间隔时间:

server:
  port: 8001
spring:
  application:
#    name: Cloud-provider-payment8001
     name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
  instance: #重点,和client平行
    instance-id: payment8001 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 访问路径可以显示ip地址
    # Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
    least-renewal-interval-in-seconds: 1
    # Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
    least-expiration-duration-in-seconds: 2

修改 Eureka Client —Cloud-provider-payment8002模块的 心跳间隔时间:

server:
  port: 8002
spring:
  application:
#    name: Cloud-provider-payment8002
    name: cloud-provider-service  # 这次重点是这里,两个要写的一样,这是这个集群的关键
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springcloud-tigerhhzz?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.tigerhhzz.springcloud.entities  # 所有Entity 别名类所在包
eureka:
  client:
    # 注册进 Eureka 的服务中心
    register-with-eureka: true
    # 检索 服务中心 的其它服务
    fetch-registry: true
    service-url:
      # 设置与 Eureka Server 交互的地址
#      defaultZone: http://localhost:7001/eureka/  #单机版
       defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/ #集群版
  instance: #重点,和client平行
    instance-id: payment8002 # 每个提供者的id不同,显示的不再是默认的项目名
    prefer-ip-address: true # 访问路径可以显示ip地址
    # Eureka客户端像服务端发送心跳的时间间隔,单位s,默认30s
    least-renewal-interval-in-seconds: 1
    # Rureka服务端在收到最后一次心跳后等待时间上线,单位为s,默认90s,超时将剔除服务
    least-expiration-duration-in-seconds: 2

6.3 eureka配置项

在注册服务之后,服务提供者会维护一个心跳用来持续高速Eureka Server,“我还在持续提供服务”,否则Eureka Server的剔除任务会将该服务实例从服务列表中排除出去。我们称之为服务续约。

面是服务续约的两个重要属性:

(1)eureka.instance.lease-expiration-duration-in-seconds

leaseExpirationDurationInSeconds,表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance。

默认为90秒

如果该值太大,则很可能将流量转发过去的时候,该instance已经不存活了。

如果该值设置太小了,则instance则很可能因为临时的网络抖动而被摘除掉。

该值至少应该大于leaseRenewalIntervalInSeconds

(2)eureka.instance.lease-renewal-interval-in-seconds

  • leaseRenewalIntervalInSeconds,表示eureka client发送心跳给server端的频率。如果在leaseExpirationDurationInSeconds后,server端没有收到client的心跳,则将摘除该instance。除此之外,如果该instance实现了HealthCheckCallback,并决定让自己unavailable的话,则该instance也不会接收到流量。
    默认30秒
  • eureka.client.registry-fetch-interval-seconds :表示eureka client间隔多久去拉取服务注册信息,默认为30秒,对于api-gateway,如果要迅速获取服务注册状态,可以缩小该值,比如5秒
  • eureka.server.enable-self-preservation
    是否开启自我保护模式,默认为true。

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。

Eureka通过“自我保护模式”来解决这个问题——当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

eureka.server.eviction-interval-timer-in-ms

eureka server清理无效节点的时间间隔,默认60000毫秒,即60秒

Eureka停更说明:2.0后停更了。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
人工智能 Cloud Native 安全
DeepSeek + Higress AI 网关/Spring AI Alibaba 案例征集
诚挚地感谢每一位持续关注并使用 Higress 和 Spring AI Alibaba 的朋友,DeepSeek + Higress AI 网关/Spring AI Alibaba 案例征集中。
124 16
|
23天前
|
存储 人工智能 开发框架
Spring AI Alibaba 应用框架挑战赛圆满落幕,恭喜获奖选手
第二届开放原子大赛 Spring AI Alibaba 应用框架挑战赛决赛于 2 月 23 日在北京圆满落幕。
|
1月前
|
人工智能 Java API
支持 40+ 插件,Spring AI Alibaba 简化智能体私有数据集成
通过使用社区官方提供的超过 20 种 RAG 数据源和 20 种 Tool Calling 接口,开发者可以轻松接入多种外部数据源(如 GitHub、飞书、云 OSS 等)以及调用各种工具(如天气预报、地图导航、翻译服务等)。这些默认实现大大简化了智能体的开发过程,使得开发者无需从零开始,便可以快速构建功能强大的智能体系统。通过这种方式,智能体不仅能够高效处理复杂任务,还能适应各种应用场景,提供更加智能、精准的服务。
|
1天前
|
负载均衡 Dubbo Java
Spring Cloud Alibaba与Spring Cloud区别和联系?
Spring Cloud Alibaba与Spring Cloud区别和联系?
|
3月前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
4月前
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
98 3
|
4月前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
3月前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
370 69
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
1月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
|
4月前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
118 1
服务架构的演进:从单体到微服务的探索之旅

热门文章

最新文章