微服务框架 SpringCloud微服务架构3

发布时间 2023-12-28 20:08:12作者: 爵岚

微服务框架 SpringCloud微服务架构

3 Eureka

3.1 提供者与消费者

3.1.1 一些概念
  • 服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
  • 服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)

在我们的Demo案例中 

 很明显两者是如下的关系:

3.1.2 一个问题

假设现在服务A调用服务B,服务B调用服务C,那么服务B是什么角色?

【相对概念】【抛开业务来谈提供者和消费者的概念是不应该的,即一个服务既可以是提供者也可以是消费者】

3.1.3 总结

服务调用关系

  • 服务提供者:暴露接口给其它微服务调用
  • 服务消费者:调用其它微服务提供的接口
  • 提供者与消费者角色其实是相对的
  • 一个服务可以同时是服务提供者和服务消费者.

Eureka 3.2 Eureka 原理分析

3.2.1 服务调用出现的问题

在我们之前的Demo 案例中,出现了下图所示的调用情况

 而且是采用硬编码的形式,把IP和端口告诉order 服务

 这样也很容易地就带来一些问题,这样写死了,环境改变了怎么办?耦合度巨高

而且随着服务的高并发,user 服务可能会部署成多个实例,

 这样时候,硬编码咋办?【所以这里一定不能用硬编码】

【归结一个问题:服务消费者到底应该如何获取服务提供者的地址信息?】

而且有一天,咱们真的拿到了它们每台的地址,有多个服务提供者的情况,消费者又该如何选择?

而且,消费者又如何得知服务提供者的健康状态? 【…一堆的问题】

 【这个时候就可以请出 Eureka了】

3.2.2 Eureka 的作用

一个服务端,一个客户端

在每一个 user-service 和 order-service 启动的那一刻,会把自己的信息注册给Eureka

 现在当有消费者想要消费服务时,就直接找Eureka

这样第一个问题 【服务消费者到底应该如何获取服务提供者的地址信息】 就解决了

接着通过负载均衡,从三个中挑一个出来

 再接下去,就可以发请求了 

 【怎么保证服务是健康的?】

 心跳续约,每30 s 一次,来让注册中心确认自己的状态

 如果说有天 user-service 8083 没跳了,注册中心就会把它从信息中删除

order-service 再次拉取服务信息时,就不会拉到8083 了

 【即消费者可以监控到服务提供者的状态】

回顾一下“三个问题”

1、消费者该如何获取服务提供者具体信息?

  • 服务提供者启动时向eureka注册自己的信息
  • eureka保存这些信息
  • 消费者根据服务名称向eureka拉取提供者信息

2、如果有多个服务提供者,消费者该如何选择?

  • 服务消费者利用负载均衡算法,从服务列表中挑选一个

3、消费者如何感知服务提供者健康状态?

  • 服务提供者会每隔30秒向EurekaServer发送心跳请求,报告健康状态
  • eureka会更新记录服务列表信息,心跳不正常会被剔除
  • 消费者就可以拉取到最新的信息

3.2.3 总结

在Eureka架构中,微服务角色有两类:

  • EurekaServer:服务端,注册中心
    •   记录服务信息
    •   心跳监控
  • EurekaClient:客户端
    • Provider:服务提供者,例如案例中的 user-service
      •   注册自己的信息到EurekaServer
      •   每隔30秒向EurekaServer发送心跳
    •   consumer:服务消费者,例如案例中的 order-service
      • 根据服务名称从EurekaServer拉取服务列表
      • 基于服务列表做负载均衡,选中一个微服务后发起远程调用

Eureka 3.3 搭建 Eureka 服务

3.3 搭建 Eureka 服务

3.3.1 动手实践

三件事

 

 3.3.2 搭建EurekaServer

搭建EurekaServer 服务步骤如下

注意:

 由于 Spring Boot 3.0,Spring Boot 2.7~2.4 和 2.4 以下版本之间变化较大,目前企业级客户老项目相关 Spring Boot 版本仍停留在 Spring Boot 2.4 以下,为了同时满足存量用户和新用户不同需求,社区以 Spring Boot 3.0 和 2.4 分别为分界线,同时维护 2022.x、2021.x、2.2.x 三个分支迭代。如果不想跨分支升级,如需使用新特性,请升级为对应分支的新版本。 为了规避相关构建过程中的依赖冲突问题,

2022.x 分支

适配 Spring Boot 3.0,Spring Cloud 2022.x 版本及以上的 Spring Cloud Alibaba 版本按从新到旧排列如下表(最新版本用*标记): (注意,该分支 Spring Cloud Alibaba 版本命名方式进行了调整,未来将对应 Spring Cloud 版本,前三位为 Spring Cloud 版本,最后一位为扩展版本,比如适配 Spring Cloud 2022.0.0 版本对应的 Spring Cloud Alibaba 第一个版本为:2022.0.0.0,第个二版本为:2022.0.0.1,依此类推)

 

Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version

2022.0.0.0-RC2*

Spring Cloud 2022.0.0

3.0.2

2022.0.0.0-RC1

Spring Cloud 2022.0.0

3.0.0

2021.x 分支

适配 Spring Boot 2.4,Spring Cloud 2021.x 版本及以上的 Spring Cloud Alibaba 版本按从新到旧排列如下表(最新版本用*标记):

Spring Cloud Alibaba VersionSpring Cloud VersionSpring Boot Version

2021.0.5.0*

Spring Cloud 2021.0.5

2.6.13

2021.0.4.0

Spring Cloud 2021.0.4

2.6.11

2021.0.1.0

Spring Cloud 2021.0.1

2.6.3

2021.1

Spring Cloud 2020.0.1

2.4.2

① 创建项目,引入spring-cloud-starter-netflix-eureka-server的依赖

直接在已有工程中创建一个新的模块 

 

 导入依赖Pom.xml

<?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>
    <groupId>com.tongda</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <!-- 这里控制了 springcloud 的版本-->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.7.8</spring-boot.version>
        <spring-cloud.version>2021.0.5</spring-cloud.version>
    </properties>

    <dependencies>
        <!-- eureka 注册中心的服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

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

    <!-- 依赖管理,cloud 的依赖-->
    <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>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>com.tongda.EurekaServerApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
修改启动类 

 

修改配置文件

 

访问测试

分析端口 8761

Eureka-Server 不仅提供让别人注册的功能,它也能注册到别人里面,自己注册自己
所以,在启动项目时,默认会注册自己,我们也可以关掉这个功能 
那么往哪个地址注册自己呢?我们看一下源码

 

 

4.2 搭建 Eureka-client

4.2.1 创建项目 client-a 选择 依赖.

 

分析 pom.xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

 

修改启动类

 

修改配置文件
# 应用服务 WEB 访问端口没有要求、随意
server:
  port: 8080
spring:
  application:
    name: eureka-client
# 注册的含义是什么?就是将自己的一些信息(什么信息IP port....)发送过去(发到那里)
eureka:
  client:
    service-url:  # 指定注册地址
      defaultZone: http://localhost:8761/eureka 
4.2.5 访问测试 
http://localhost:8761 

 

4.2.6 再创建项目 client-b
如 client-a 一样,这里就不贴多余截图了,注意端口和服务名以及启动类上的注解,在测试
查看是否注册上去,在 eureka 里面是通过 spring.application.name 来区分服务的

 

4.3 同一个服务(客户端)启动多台
4.3.1 IDEA 启动多台服务操作

 

 

4.3.2 访问查看 

 

4.4 注册中心的状态认识

UP: 服务是上线的,括号里面是具体服务实例的个数,提供服务的最小单元
DOWN: 服务是下线的
UN_KONW: 服务的状态未知

4.4.1 服务的实例名称 

 

 

4.5 常用配置文件设置 

 

4.5.1 server 中常用的配置 

# 单机
server:
  port: 8761 # eureka默认端口

spring:
  application:
    name: eurekaserver # eureka的服务名称,不要使用特殊字符
eureka:  # eureka的配置分为三类server client 实例的
  client:
    service-url:  # eureka的地址信息
#      defaultZone: http://localhost:8761/eureka
      #  避免写死
      defaultZone: ${EUREKA_SERVER_URL:http://localhost:8761/eureka}
#    register-with-eureka: false #先将server自己注册自己的开关 关掉
    register-with-eureka: ${REGISTER-WITH-EUREKA:true} #先将server自己注册自己的开关 关掉
    fetch-registry: true
# docker run -p 端口 -d 后台运行 --link 指定网络host文件映射的 -e MYSQL_ROOT_PASSWORD=123456 临时指定 -v 文件挂载

  server:
    eviction-interval-timer-in-ms: 10000  #服务器间隔多少毫秒做定期删除的操作
    renewal-percent-threshold: 0.85  #续约百分比,超过85%的应用没有和你续约,那么eureka会保护服务,不会剔除任何一个
  instance: # 实例的配置
    # instance-id: localhost:eureka-server:8761 # 主机名称:应用名称:端口号
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} # 避免写死
    hostname: localhost # 主机名称或者服务的ip
    prefer-ip-address: true # 以ip的形式显示具体的服务信息
    lease-renewal-interval-in-seconds: 5 # 服务实例的续约的时间间隔

#集群
#server:
#  port: 8761
#spring:
#  application:
#    name: eureka-server
#eureka:
#  client:
#    service-url: # 不写会自动注册8761
#      defaultZone: http://localhost:8762/eureka,http://localhost:8763/eureka
#
#  instance: # 实例的配置
#    # instance-id: localhost:eureka-server:8761 # 主机名称:应用名称:端口号
#    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} # 避免写死
#    hostname: localhost # 主机名称或者服务的ip,此处为集群主机名可以不写
#    prefer-ip-address: true # 以ip的形式显示具体的服务信息
#    lease-renewal-interval-in-seconds: 5 # 服务实例的续约的时间间隔

#集群终极方案
#server:
#  port: 8761 # eureka的默认端口
#spring:
#  application:
#    name: eureka-server # 应用名称,不要使用特殊字符
#eureka:
#  client:
#    service-url: #不写默认端口8761
##      defaultZone: http://peer1:8761/eureka,http://peer2:8762/eureka,http://peer3:8763/eureka
#      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka,http://localhost:8763/eureka
#  instance:
#    instance-id: ${spring.application.name}:${server.port} #主机名称:应用名称:端口
##    hostname: peer1 # 主机名称或者服务的ip,此处为集群主机名可以不写
#    prefer-ip-address: true  # 以ip的形式显示具体的服务信息
#    lease-renewal-interval-in-seconds: 5 # 服务实例的续约的时间间隔

4.5.2 client 中常用的配置

server:
  port: 8763
spring:
  application:
    name: eureka-server # 集群时应用名称不能改
eureka:
  client:
    service-url: # eureka 服务端和客户端的交互地址,集群用,隔开
      defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka
    register-with-eureka: true #注册自己
    fetch-registry: true #拉取服务列表
    registry-fetch-interval-seconds: 5 # 表示 eureka-client 间隔多久去拉取服务注册信息

  instance: # 实例的配置
    # instance-id: localhost:eureka-server:8761 # 主机名称:应用名称:端口号
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port} # 避免写死
    hostname: localhost # 主机名称或者服务的ip
    prefer-ip-address: true # 以ip的形式显示具体的服务信息
    lease-renewal-interval-in-seconds: 5 # 服务实例的续约的时间间隔
    lease-expiration-duration-in-seconds: 20 #表示 eureka server 至上一次收到 client 的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该实例

5.构建高可用的 Eureka-Server 集群

  1、中心化集群

  2、主从模式集群

  3、去中心化集群:高可用

在去中心化模式中没有主从的概念,自己可以注册自己,实现两两注册达到高可用集群 

 

5.1 对刚才的 eureka-server 修改配置文件

5.1.1 server-1 

 

5.1.2 server-2

 

 

 

 

 

集群的深刻理解