Spring Cloud开发实战(一)- 搭建一个Eureka+Feign+LoadBalancer 项目

news2024/11/14 3:10:50

Spring Cloud开发实战(一)- 搭建一个Eureka+Feign+LoadBalancer 项目

文章目录

  • Spring Cloud开发实战(一)- 搭建一个Eureka+Feign+LoadBalancer 项目
    • 0.内容简介
    • 1.Eureka服务注册与发现
      • 1.1.什么是服务注册与发现
      • 1.2.Eureka注册中心
        • 1.2.1.新建项目,添加依赖
        • 1.2.2.启动类
        • 1.2.3.配置文件
        • 1.2.4.通过运行启动类EurekaServerApplication
      • 1.3.Eureka相关配置
        • 1.3.1.注册中心配置
          • (1)eureka.server.enable-self-preservation
          • (2)eureka.server.eviction-interval-timer-in-ms
        • 1.3.2.微服务提供者配置
          • (1)eureka.instance.hostname
          • (2)eureka.instance.appname
          • (3)eureka.instance.ip-address
          • (4)eureka.instance.prefer-ip-address
          • (5)eureka.instance.lease-renewal-interval-in-seconds
          • (6)eureka.instance.lease-expiration-duration-in-seconds
          • (7)eureka.instance.status-page-url-path
          • (8)eureka.instance.status-page-url
          • (9)eureka.instance.health-check-url-path
          • (10)eureka.instance.health-check-url
          • (11)eureka.instance.instance-id
          • (12)eureka.instance.status-page-url-path
          • (13)eureka.instance.health-check-url-path
        • 1.3.3.注册中心客户端配置
          • (1)eureka.client.register-with-eureka
          • (2)eureka.client.fetch-registry
          • (3)eureka.client.registery-fetch-interval-seconds
          • (4)eureka.client.eureka-server-connect-timeout-seconds
          • (5)eureka.client.eureka-server-read-timeout-seconds
          • (6)eureka.client.eureka-connection-idle-timeout-seconds
          • (7)eureka.client.filter-only-up-instances
          • (8)eureka.client.service-url.defaultZone
          • (9)eureka.client.serviceUrl.*
    • 2.微服务提供者
      • 2.1.pom.xml
      • 2.2.启动类
      • 2.3.配置文件
      • 2.4.Eureka Server应用事件
      • 2.5.健康状态
    • 3.配置中心
      • 3.1.服务端
        • 3.1.pom.xml
        • 3.2.启动类
        • 3.3.配置文件
        • 3.4.启动服务
        • 3.5.查看示例配置文件
      • 3.2.客户端
        • 3.2.1.pom.xml
        • 3.2.2.启动类
        • 3.2.3.配置文件
        • 3.2.4.测试配置类
        • 3.2.5.启动服务,查看结果
    • 4.RPC远程调用
      • 4.1.RESTfull 风格简介
      • 4.2.RestT emplate 远程调用
      • 4.3.Feign远程调用
        • 4.3.1.pom.xml
        • 4.3.2.启动类
        • 4.3.3.配置文件
        • 4.3.4.远程接口
        • 4.3.5.启动服务,查看结果
    • 5.负载均衡
      • 5.1.LoadBalancer依赖导入
      • 5.2.负载均衡配置
      • 5.3.启动类
      • 5.4.重试机制配置
    • 6.RPC调用保护
      • 6.1.失败回退
        • 6.1.1.定义和使用一个 Fallback 回退处理类
        • 6.1.2.定义和使用一个FallbackFactory回退处理工厂类
        • 6.1.3.测试输出的内容
      • 6.2.熔断
        • 6.2.1.熔断器
        • 6.2.2.导入依赖
        • 6.2.3.相关配置
        • 6.2.4.测试结果

0.内容简介

前言:本文内容源于 《Java高并发核心编程(卷3)尼恩著》第3章,有兴趣的读者可以去原书籍中阅读一下。

Spring Cloud全家桶是Pivotal团队提供的一整套微服务开源解决方案,包括服务注册与发现、配置中心、全链路监控、服务网关、负载均衡、熔断器等组件。以上组件主要是通过对Netflix OSS套件中的组件进行整合完成的,该开源子项目叫作spring-cloud-netflix,其中比较重要的组件有:

  • spring-cloud-netflix-Eureka:注册中心。

  • spring-cloud-netflix-hystrix:RPC保护组件。

  • spring-cloud-netflix-ribbon:客户端负载均衡组件。

  • spring-cloud-netflix-zuul:内部网关组件。

Spring Cloud全家桶技术栈除了对Netflix OSS的开源组件做整合之外,还整合了一些选型中立的开源组件。比如,Spring Cloud ZooKeeper组件整合了ZooKeeper,提供了另一种方式的服务发现和配置管理。

Spring Cloud架构中的单体业务服务基于Spring Boot应用。 Spring Boot是由Pivotal团队提供的全新框架,用来简化新Spring应用的初始搭建以及开发过程。Spring Cloud与Spring Boot是什么关系呢?

  • Spring Cloud利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发。

  • Spring Boot专注于快速方便地开发单体微服务提供者,而Spring Cloud解决的是各微服务提供者之间的协调治理关系。

  • Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,它依赖Spring Boot而存在。

最终,Spring Cloud将Spring Boot开发的一个个单体微服务整合并管理起来,为各单体微服务提供配置管理、服务发现、熔断器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等基础的分布式协助能力。

1.Eureka服务注册与发现

1.1.什么是服务注册与发现

从宏观角度,微服务架构下的系统角色可以简单分为服务注册中心(Registration Center)、微服务提供者(Service Provider)、远程客户端组件(Service Consumer)。

  • 服务注册:微服务提供者将自己的服务信息(如服务名、IP地址等) 告知服务注册中心。

  • 服务发现:注册中心客户端组件从注册中心查询所有的微服务提供者信息, 当其他的服务下线后,服务注册中心能够告知注册中心客户端组件。

远程客户端组件与微服务提供者之间一般使用某种RPC通信机制来进行服务消费, 常见的RPC通信方式为REST API, 底层为HTTP传输协议。 微服务提供者通常以Web服务的方式提供REST API接口;远程客户端组件则通常以模块组件的方式完成REST API的远程调用。

注册中心、微服务提供者、远程客户端组件之间的关系大致如下图所示。

注册中心的主要功能如下:

  1. 服务注册表维护:这是注册中心的核心,用来记录各个微服务提供者实例的状态信息。注册中心提供Provider实例清单的查询和管理API,用于查询可用的Provider实例列表,管理Provider实例的上线和下线。
  2. 服务健康检查: 注册中心使用一定机制定时检测已注册的Provider实例, 如发现某实例长时间无法访问,就会从服务注册表中移除该实例。

微服务提供者的主要功能如下:

  1. 服务注册:服务注册是指Provider微服务实例在启动时将自己的信息注册到注册中心上的过程。
  2. 心跳续约:Provider实例会定时向服务注册中心提供“心跳”,以表明自己还处于可用的状态。当一个Provider实例停止心跳一段时间后,注册中心会认为该服务实例不可用了,就会将该服务实例从服务注册列表中剔除。 如果被剔除的Provider实例过一段时间后继续向注册中心提供心跳,那么服务注册中心会将该Provider实例重新加入服务注册表中。
  3. 健康状况查询: Provider实例能提供健康状况查看的API, 注册中心或者其他的微服务Provider能够获取其健康状况。

微服务提供者的服务注册和心跳续约一般都会通过注册中心客户端组件来完成。 注册中心客户端组件还有如下功能:

  1. 服务发现:从注册中心查询可用Provider实例清单。
  2. 实例缓存: 将从注册中心查询到的Provider实例清单缓存到本地, 不需要在每次使用时都去注册中心临时获取。

1.2.Eureka注册中心

Eureka本身是Netflix开源的一款注册中心产品, 并且Spring Cloud提供了相应的集成封装, 选择它作为注册中心的讲解实例是出于以下原因:

  • Eureka在业界的应用十分广泛(尤其是国外),整个框架也经受住了Netflix严酷生产环境的考验。

  • 除了Eureka注册中心, Netflix的其他服务治理功能也十分强大, 包括Ribbon、 Hystrix、 Feign、Zuul等组件结合到一起组成了一套完整的服务治理框架,使得服务的调用、路由变得异常容易。

1.2.1.新建项目,添加依赖

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.ahao.project</groupId>
    <artifactId>eureka-registration-center</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Eureka Registration Center</name>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>3.0.0</version>
<!-- 
 		本人在启动时遇到了jackson和gson的相关异常,所以手动排除了以下依赖,并导入了其他版本。
		- java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/ser/std/ToStringSerializerBase
		- Correct the classpath of your application so that it contains a single, compatible version of com.google.gson.GsonBuilder
-->     
<!--            <exclusions>-->
<!--                <exclusion>-->
<!--                    <groupId>com.fasterxml.jackson.core</groupId>-->
<!--                    <artifactId>jackson-databind</artifactId>-->
<!--                </exclusion>-->
<!--                <exclusion>-->
<!--                    <groupId>com.fasterxml.jackson.core</groupId>-->
<!--                    <artifactId>jackson-core</artifactId>-->
<!--                </exclusion>-->
<!--                <exclusion>-->
<!--                    <groupId>com.fasterxml.jackson.core</groupId>-->
<!--                    <artifactId>jackson-annotations</artifactId>-->
<!--                </exclusion>-->
<!--                <exclusion>-->
<!--                    <groupId>com.google.code.gson</groupId>-->
<!--                    <artifactId>gson</artifactId>-->
<!--                </exclusion>-->
<!--            </exclusions>-->
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.1</version>
        </dependency>
    </dependencies>

</project>
1.2.2.启动类
package org.ahao.project;

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

// 声明这个应用是一个Eureka Server
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class,args);
    }
}
1.2.3.配置文件
server:
  port: 7777
spring:
  application:
    name: registration-center

eureka: # eureka配置
  client:
    fetch-registry: false
    register-with-eureka: false
    service-url:
      defaultZone: ${SCAFFOLD_EUREKA_ZONE_HOSTS:http://localhost:7777/eureka/} # 服务注册中心的配置内容,指定服务注册中心的位置
  instance:
  hostname: ${EUREKA_ZONE_HOSTS:localhost}
  server:
    enable-self-preservation: true #开启自我保护
    eviction-interval-timer-in-ms: 60000 # 扫描失效服务的间隔时间(单位为毫秒)

以上的配置文件中包含3类配置项: 作为服务注册中心的配置项 (eureka.server.*) 、 作为Provider提供者的配置项(eureka.instance.*)、作为注册中心客户端组件的配置项(eureka.client.*)。

1.2.4.通过运行启动类EurekaServerApplication

控制台日志输出如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

浏览器输入http://localhost:7777/访问Eureka。

在这里插入图片描述

实际上一个Eureka Server实例身兼三个角色:注册中心、微服务提供者、注册中心客户端,主要原因如下:

1) 对于所有Provider Instance而言,Eureka Server的角色是注册中心。

2) 对于Eureka Server集群中其他的Eureka Server而言, Eureka Server的角色是注册中心客户端。

3) Eureka Server对外提供REST接口的服务,当然也是微服务提供者。

1.3.Eureka相关配置

1.3.1.注册中心配置
(1)eureka.server.enable-self-preservation

此配置项用于设置是否关闭注册中心的保护机制。什么是保护机制呢?Eureka Server会定时统计15分钟之内心跳成功的Provider实例的比例,如果低于85%将会触发保护机制,处于保护状态的Eureka Server不剔除失效的微服务提供者。enable-self-preservation的默认值为true,表示开启自我保护机制。 如果15分钟之内心跳成功的Provider实例的比例高于85%, 那么Eureka Server仍然会处于正常状态。

(2)eureka.server.eviction-interval-timer-in-ms

配置Eureka Server清理无效节点的时间间隔,默认为60000毫秒(即60秒)。但是,如果EurekaServer处于保护状态,此配置就无效。

1.3.2.微服务提供者配置
(1)eureka.instance.hostname

设置当前实例的主机名称。

(2)eureka.instance.appname

设置当前实例的服务名称。 默认值取自spring.application.name配置项的值, 如果该选项没有值, 则eureka.instance.appname值为unknown。在Eureka服务器上,微服务提供者的名称不区分字母大小写。

(3)eureka.instance.ip-address

设置当前实例的IP地址。

(4)eureka.instance.prefer-ip-address

如果配置为true, 就使用IP地址的形式来定义Provider实例的访问地址, 而不使用主机名来定义Provider实例的地址。如果同时设置了eureka.instance.ip-address选项,就使用该选项所配置的IP,否则自动获取网卡的IP地址。 默认情况下, 此配置项的值为false, 使用主机名来定义Provider实例的访问地址。

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

定义Provider实例到注册中心续约(心跳)的时间间隔,单位为秒,默认值为30秒。

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

定义Provider实例失效的时间,单位为秒,默认值为90秒。

(7)eureka.instance.status-page-url-path

定义Provider实例状态页面的URL, 此选项所配置的是相对路径, 默认使用HTTP访问, 如果需要使用HTTPS则使用绝对路径配置。默认的相对路径为/info。

(8)eureka.instance.status-page-url

定义Provider实例状态页面的URL,此选项配置的是绝对路径。

(9)eureka.instance.health-check-url-path

定义Provider实例健康检查页面的URL, 此选项所配置的是相对路径, 默认使用HTTP访问, 如果需要使用HTTPS则使用绝对路径配置。默认的相对路径为/health。

(10)eureka.instance.health-check-url

定义Provider实例健康检查页面的URL,此选项配置的是绝对路径。

(11)eureka.instance.instance-id

此项用于配置Provider实例ID,如果不进行ID配置,默认值的格式如下:${spring.cloud.client.hostname}:${spring.application.name}:${server.port}}翻译过来就是“主机名:服务名称:服务端口”。

(12)eureka.instance.status-page-url-path

定义Provider实例状态页面的URL, 此选项配置的是相对路径, 默认使用HTTP访问, 如果需要使用HTTPS,就使用绝对路径配置。默认的相对路径为/info。

(13)eureka.instance.health-check-url-path

定义Provider实例健康检查页面的URL, 此选项配置的是相对路径, 默认使用HTTP访问, 如果需要使用HTTPS,就使用绝对路径配置。默认的相对路径为/health。

1.3.3.注册中心客户端配置
(1)eureka.client.register-with-eureka

作为Eureka Client, eureka.client.register-with-eureka表示是否将自己注册到其他的Eureka Server,默认为true。

(2)eureka.client.fetch-registry

作为Eureka Client,是否从Eureka Server获取注册信息,默认为true。因为本例是一个单点的Eureka Server,不需要同步其他Eureka Server节点数据,所以设置为false。

(3)eureka.client.registery-fetch-interval-seconds

作为Eureka Client,从Eureka Server获取注册信息的间隔时间,单位为秒,默认值为30秒。

(4)eureka.client.eureka-server-connect-timeout-seconds

Eureka Client组件连接Eureka Server的超时时间,单位为秒,默认值为5秒。

(5)eureka.client.eureka-server-read-timeout-seconds

Eureka Client组件读取Eureka Server信息的超时时间,单位为秒,默认值为8秒。

(6)eureka.client.eureka-connection-idle-timeout-seconds

Eureka Client组件到Eureka Server连接空闲关闭的时间,单位为秒,默认值为30秒。

(7)eureka.client.filter-only-up-instances

从Eureka Server获取Provider实例清单时是否进行过滤,只保留UP状态的实例,默认值为true。

(8)eureka.client.service-url.defaultZone

作为Eureka Client,需要向远程的Eureka Server自我注册、发现其他的Provider实例。此配置项用于设置Eureka Server的交互地址,在注册中心集群的情况下,多个Eureka Server之间可以使用半角逗号分隔。

此配置项涉及Spring Cloud中Region(地域)与Zone(可用区)两个概念,两者都借鉴AWS(Amazon云)的概念。在非AWS环境下,Region和Zone(Availability Zone)可以理解为服务器的位置,即Region可以理解为服务器所在的地域,Zone可以理解成服务器所处的机房。一个Region地域可以包含多个Zone机房。不同的Region地域的距离很远,一个Region地域的不同Zone间的距离往往较近,也可能在同一个物理机房内。

在网络环境跨地域、 跨机房的情况下, Region与Zone都可以在配置文件中进行配置。 配置Region与Zone的主要目的是,在网络环境复杂的情况下帮助客户端就近访问需要的Provider实例。负载均衡组件Spring Cloud Ribbon的默认策略是优先访问同客户端处于同一个Zone中的服务端实例,只有当同一个Zone中没有可用服务端实例时,才会访问其他Zone中的实例。

如果网络环境不复杂,比如所有服务器都在于同一个地域同一个机房,就不需要配置Region与Zone。如果不配置Region地域选项值,那么其默认值为us-east-1;如果不配置Zone的Key值,那么其默认的Key值为defaultZone。 可以通过eureka.client.serviceUrl.defaultZone选项设置默认Zone的注册中心Eureka Server的访问地址。

Spring Cloud的注册中心地址是以Zone为单位进行配置的,一个Zone如果有多个注册中心,就要使用逗号隔开。 如果有多个机房, 就配置多个eureka.client.serviceUrl.ZoneName配置项。 举个例子,假设在北京区域有两个机房,每个机房有一个注册中心Eureka Server,那么Eureka Server配置文件中有关Zone和注册中心的配置大致如下:

client:
	region: 'Beijing #指定Region区域为北京
	availabilityZones:
		Beijing: 'zone-2,zone-1 #指定北京的机房为zone-2,zone-1
	serviceUrl:
		zone-1: http://localhost:7777/eureka/ # zone-1机房的Eureka Server
		zone-2: http://localhost: 7778/eureka/ # zone-2机房的Eureka Server

在配置服务注册中心地址时,如果Eureka Server加入了安全验证,则注册中心的URL格式为:

http://<username>:<password>@localhost:8761/eureka

其中<username>为安全校验的用户名,<password>为该用户的密码。

(9)eureka.client.serviceUrl.*

此配置项是上面第(8)项的上一级配置项,用于在多个Zone的场景下配置服务注册中心,其类型为HashMap,key为Zone,Value为机房中的所有注册中心地址。如果没有多个Zone,那么此配置项有一个默认的可用区,Key为defaultZone。

2.微服务提供者

2.1.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.ahao.project</groupId>
    <artifactId>eureka-provider</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Eureka Provider A</name>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--  选择 spring-cloud-starter-netflix-eureka-client 对应的版本 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.1</version>
        </dependency>
        <!-- actuator 模块提供了生产级别的功能,比如健康检查,审计,指标收集,HTTP跟踪等。 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>3.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-annotations</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.google.code.gson</groupId>
                    <artifactId>gson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>

2.2.启动类

// 启用Eureka Client客户端组件
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }

}

2.3.配置文件

spring:
  application:
    name: provider
server:
  port: 7001
  servlet:
    context-path: /provider

management:
  endpoints:
    enabled-by-default: true
    web:
      exposure:
        include: info,health # 暴露的端点
      base-path: /monitor # 监控路径配置


eureka:  # eureka配置
  instance:
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    ip-address: ${spring.cloud.client.ip-address}
    prefer-ip-address: true #访问路径优先使用IP地址
    status-page-url-path: ${server.servlet.context-path}${management.endpoints.web.base-path}/info
    health-check-url-path: ${server.servlet.context-path}${management.endpoints.web.base-path}/health
  client:
    client:
    register-with-eureka: true #注册到eureka服务器
    fetch-registry: true #是否去注册中心获取其他服务
    serviceUrl:
      defaultZone: http://${EUREKA_ZONE_HOST:localhost}:7777/eureka/

2.4.Eureka Server应用事件

Eureka Server提供了多个和Provider Instance相关的Spring上下文应用事件 (ApplicationEvent) 。当Server启动、服务注册、服务下线、服务续约等事件发生时,Eureka Server会发布相对应的应用事件,以方便应用程序监听。

下面是几个常见的Eureka Server应用事件:

  • EurekaInstanceRenewedEvent:服务续约事件。

  • EurekaInstanceRegisteredEvent:服务注册事件。

  • EurekaInstanceCanceledEvent:服务下线事件。

  • EurekaRegistryAvailableEvent:Eureka注册中心启动事件。

  • EurekaServerStartedEvent:Eureka Server启动事件。

如果需要监听Provider Instance的服务注册、服务下线、服务续约等事件,那么可以在Eureka注册中心编写相应的事件监听程序,如下所示:

@Component
@Slf4j
public class DebugEurekaEventListener {

    @EventListener
    public void listen(EurekaInstanceCanceledEvent event){
        log.info("服务下线:{},{}",event.getServerId(),event.getAppName());
    }

    @EventListener
    public void listen(EurekaInstanceRegisteredEvent event){
        log.info("服务上线:{},{}",event.getInstanceInfo().getId(),event.getInstanceInfo().getAppName());
    }

    @EventListener
    public void listen(EurekaInstanceRenewedEvent event){
        log.info("服务心跳续约:{},{}",event.getInstanceInfo().getId(),event.getInstanceInfo().getAppName());
    }

    @EventListener
    public void listen(EurekaServerStartedEvent event){
        log.info("Eureka Server Start");
    }
}

日志输出如下:

在这里插入图片描述

2.5.健康状态

Eureka Server并不记录Provider的所有健康状况信息,仅仅维护了一个Provider清单。EurekaClient组件查询的Provider提供者注册清单中,包含每个Provider的健康状况的检查地址。通过该健康状况的地址可以查询Provider提供者的健康状况。

在这里插入图片描述

通过Eureka Server的/apps/{provider-id}接口地址, 可以获取某个Provider实例的详细信息。 获取Provider中详细信息的URL:http://localhost:7777/eureka/apps/provider

在浏览器输入该地址,返回的响应如下:

<application>
<name>PROVIDER</name>
<instance>
<instanceId>10.4.66.24:7001</instanceId>
<hostName>10.4.66.24</hostName>
<app>PROVIDER</app>
<ipAddr>10.4.66.24</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">7001</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1722249412925</registrationTimestamp>
<lastRenewalTimestamp>1722249923233</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1722249412351</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>7001</management.port>
</metadata>
<homePageUrl>http://10.4.66.24:7001/</homePageUrl>
<statusPageUrl>http://10.4.66.24:7001/provider/monitor/info</statusPageUrl>
<healthCheckUrl>http://10.4.66.24:7001/provider/monitor/health</healthCheckUrl>
<vipAddress>provider</vipAddress>
<secureVipAddress>provider</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1722249412926</lastUpdatedTimestamp>
<lastDirtyTimestamp>1722249412309</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>

在Eureka Server响应的Provider的详细信息中,有3个与Provider实例的健康状态有关的信息:

  • status

status是Provider实例本身发布的健康状态。 status的值为UP表示应用程序状态正常。 除了UP外,应用健康状态还有DOWNOUT_OF_SERVICEUNKONWN等其他取值,不过只有状态为UP的Provider实例会被Eureka Client组件请求。

  • healthCheckUrl

healthCheckUrl是Provider实例的健康信息URL地址,默认为Spring Boot Actuator组件中ID为health的Endpoint(端点),其默认URL地址为/actuator/health

  • statusPageUrl

statusPageUrl是Provider实例的状态URL地址,默认为Spring Boot Actuator组件中ID为info的Endpoint(端点),其默认URL地址为/actuator/info

3.配置中心

在采用分布式微服务架构的系统中, 由于服务数量巨多, 为了便于服务配置文件统一管理, 需要分布式配置中心组件。 如果各个服务的配置分散管理, 那么上线之后配置的如何保持一致将会是一个很令人头疼的问题。因此,各个服务的配置定然需要集中管理。Spring Cloud Config配置中心是一个比较好的解决方案。使用Spring Cloud Config配置中心涉及两个部分:

  • config-server:服务端配置。

  • config-client:客户端配置。

3.1.服务端

3.1.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.ahao.project</groupId>
    <artifactId>config-server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>Config Server</name>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>

</project>
3.2.启动类
// 添加@EnableConfigServer注解,开启Config Server服务
@EnableConfigServer
@SpringBootApplication
public class ConfigServer{
    public static void main(String[] args) {
      	// 设置 spring.cloud.bootstrap.enabled=true 表示启动bootstrap配置文件
        args = Arrays.copyOf(args, args.length + 1);
        args[args.length - 1] = "--spring.cloud.bootstrap.enabled=true";
        SpringApplication.run(ConfigServer.class,args);
    }
}
3.3.配置文件
server:
  port: 8888
spring:
  application:
    name: config-server
  profiles:
    active: native # 读取本地配置文件
  cloud:
    config:
      server:
        native:
          search-locations: classpath:config/ # 声明本地配置文件存放的位置

配置说明:

  • spring.profiles.active=native:表示从本地读取配置,而不是从Git读取配置。
  • search-locations=classpath:config/:表示查找文件的路径,在类路径的config下。

服务端的配置文件放置规则: 在配置路径下,以{label}/{application}-{profile}.properties的命令规范放置对应的配置文件。

在服务端放置一个示例配置文件。

在这里插入图片描述

内容如下:

conf:
  description: 配置中心的配置文件

Config配置中心启动之后,可以使用以下的地址格式直接访问加载好的配置属性:

http://${CONFIG-SERVER-HOST}: ${CONFIG-SERVER-PORT}/{application}/{profile}[/{label}]

特别说明:Spring Cloud Config-server支持多种配置方式,比如Git、Native、SVN等。虽然官方建议使用Git方式进行配置,但是这里没有重点介绍Git方式,而是使用了本地文件的方式。有以下三个原因:

1)对于学习或者一般的开发来说,本地文件的配置方式更简化。

2)生产环境建议使用Nacos,它具备注册中心和配置中心相结合的功能,更加方便、简单。

3)掌握了Native的配置方式之后,对于Git的配置方法就能触类旁通。

3.4.启动服务

在这里插入图片描述

3.5.查看示例配置文件

地址:http://localhost:8888/conf-client/common/dev
在这里插入图片描述

3.2.客户端

3.2.1.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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.ahao.project</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>config-client</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>

</project>
3.2.2.启动类
@SpringBootApplication
public class ConfigClient {

    private static final Log logger = LogFactory.getLog(ConfigClient.class);

    public static void main(String[] args) {
        // 设置 spring.cloud.bootstrap.enabled=true 表示启动bootstrap配置文件
        args = Arrays.copyOf(args, args.length + 1);
        args[args.length - 1] = "--spring.cloud.bootstrap.enabled=true";
        ConfigurableApplicationContext run = SpringApplication.run(ConfigClient.class, args);
        TestConfig bean = run.getBean(TestConfig.class);
        logger.info("查看org.ahao.project.config.TestConfig.des的值:"+bean.getDes());
    }
}
3.2.3.配置文件
spring:
  application:
    name: conf-client #对应服务端规则中的{application}部分
  cloud:
    config:
    	enabled: true #是否从配置中心服务中读取配置
      label: dev #对应服务端规则中的{label}部分
      profile: common #对应服务端规则中的{profile}部分
      uri: http://${config.server.host}:${config.server.port}/ #配置服务中心地址(如果不使用eureka可以直接配置url路径)

config: #这是自定义的配置中心的ip和端口号
  server:
    host: localhost
    port: 8888

如果是与Eureka的客户端配合使用, 那么建议开启配置服务的自动发现机制, 使用如下的配置:

  • spring.cloud.config.discovery.enabled: true:启用发现服务功能

  • spring.cloud.config.discovery.service-id: config-server:指定配置中心名称

⚠️ 配置中心的两种发现机制(spring.cloud.config.uri和Eureka客户端自动发现)不能同时存在,二者选其一即可。

客户端config属性的相关配置,只有配置在bootstrap.properties(或bootstrap.yml)中,config部分 内 容 才 能 被 正 确 加 载 。 原 因 是 config 的 相 关 配 置 必 须 早 于 application.properties , 而bootstrap.properties的加载也是早于application.properties的。

配置文件加载优先级。

  • bootstrap.properties和bootstrap.yml: 这是最先加载的配置文件,用于配置应用程序上下文的基础设施,例如外部配置源和加密/解密。
  • application.properties和application.yml: 这是主配置文件,包含应用程序的常规配置。
  • application-{profile}.properties和application-{profile}.yml: 针对不同的环境(profile)加载相应的配置文件。例如application-dev.yml 用于开发环境,application-prod.yml 用于生产环境。

后加载的配置文件会覆盖之前加载的相同键名的配置项。

3.2.4.测试配置类
@Configuration
public class TestConfig {

    @Value("${conf.description}")
    private String des;

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }
}
3.2.5.启动服务,查看结果

在这里插入图片描述

4.RPC远程调用

4.1.RESTfull 风格简介

REST(Representational State Transfer)是Roy Fielding提出的一个描述互联系统架构风格的名词。REST定义了一组体系架构原则,可以根据这些原则设计Web服务。

RESTfull风格使用不同的HTTP方法来进行不同的操作, 并且使用HTTP状态码来表示不同的结果。如HTTP的GET方法用于获取资源,HTTP的DELETE方法用于删除资源。

HTTP协议中,大致的请求方法如下:

  • GET:通过请求URI得到资源。

  • POST:用于添加新的资源。

  • PUT:用于修改某个资源,若不存在则添加。

  • DELETE:删除某个资源。

  • OPTIONS:询问可以执行哪些方法。

  • HEAD:类似于GET,但是不返回body信息,用于检查资源是否存在,以及得到资源的元数据。

  • CONNECT:用于代理进行传输,如使用SSL。

  • TRACE:用于远程诊断服务器。

4.2.RestT emplate 远程调用

Spring Boot提供了一个很好用的REST接口远程调用组件,叫作RestTemplate模板组件。该组件提供了多种便捷访问远程REST服务的方法, 能够大大提高客户端的编写效率。 比如, 可以通过getForEntity()方法发送一个GET请求,该方法的返回值是一个ResponseEntityResponseEntity是Spring对HTTP响应的封装,包括了几个重要的元素,如响应码、contentTypecontentLength、响应消息体等。

    public static void main(String[] args) {
        // RestTemplateBuilder建造者
        RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
        // 使用建造者的build()方法,建造restTemplate实例
        RestTemplate restTemplate = restTemplateBuilder.build();
        // 请求的url:访问eureka上所有注册的应用
        String url = "http://localhost:7777/eureka/apps";
        // 第一参数表示服务器的url,第二个参数为响应体的封装类型
        ResponseEntity<String> forEntity = restTemplate.getForEntity(url, String.class);
        System.out.println("状态吗:"+forEntity.getStatusCode());
        System.out.println("响应内容:"+forEntity.getBody());
    }

结果输出:

状态吗:200 OK
响应内容:{"applications":{"versions__delta":"1","apps__hashcode":"","application":[]}}

4.3.Feign远程调用

Feign是在RestTemplate基础上封装的,使用注解的方式来声明一组与微服务提供者Rest接口所对应的本地Java API接口方法。 Feign将远程接口抽象成为一个声明式的Rest客户端,并且负责完成Rest接口和服务提供方的接口绑定。

Feign具备可插拔的注解支持,包括Feign注解和JAX-RS注解。同时,对于Feign自身的一些主要组件,比如编码器和解码器等,它也以可插拔的方式提供以便在有需求时扩张和替换它们。

4.3.1.pom.xml

前置准备:先启动Eureka注册中心和微服务提供者服务,并且微服务提供者中新增一个用来提供给外部调用的FeignProviderController。

@RestController
@RequestMapping("/feign/provider")
public class FeignProviderController {

    @GetMapping("/test/{id}")
    public String test(@PathVariable String id){
      	System.out.println("接受远程调用:"+id);
        return "远程调用:"+id;
    }

}

然后启动服务。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

<?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.ahao.project</groupId>
    <version>1.0-SNAPSHOT</version>
    <artifactId>eureka-consumer</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>3.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>3.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-annotations</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.google.code.gson</groupId>
                    <artifactId>gson</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

</project>
4.3.2.启动类
// 开启Feign客户端,扫描远程接口包
@EnableFeignClients(basePackages = "org.ahao.project.remote.inf")
@SpringBootApplication
public class EurekaConsumerApplication {

    private static final Log logger = LogFactory.getLog(EurekaConsumerApplication.class);

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(EurekaConsumerApplication.class, args);
        FeignProviderInterface bean = run.getBean(FeignProviderInterface.class);
        logger.info(bean.test("12345678"));
    }
}
4.3.3.配置文件
server:
  port: 7002
spring:
  application:
    name: consumer

eureka:
  client:
    register-with-eureka: true #注册到eureka服务器
    fetch-registry: true #是否去注册中心获取其他服务
    serviceUrl:
      defaultZone: http://${EUREKA_ZONE_HOST:localhost}:7777/eureka/
4.3.4.远程接口

注意所在的包名,和@EnableFeignClients中配置保持一致。

package org.ahao.project.remote.inf;

import org.springframework.cloud.openfeign.FeignClient;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "provider")
public interface FeignProviderInterface {
  
    /**
     * 注意此处与原本提供方接口地址/feign/provider/test/{id} 多了一个前缀/provider
     * 因为提供方服务配置了应用的上下文路径/provider
     * @param id
     * @return
     */
    @GetMapping("/provider/feign/provider/test/{id}")
    String test(@PathVariable("id") String id);
}
4.3.5.启动服务,查看结果

在这里插入图片描述

5.负载均衡

Spring Cloud Ribbon是Spring Cloud集成Ribbon开源组件的一个模块,它不像服务注册中心Eureka Server、 配置中心Spring Cloud Config那样独立部署, 而是作为基础设施模块, 几乎存在于每一个Spring Cloud微服务提供者中。 微服务间的RPC调用, 以及API网关的代理请求的RPC转发调用,实际上都需要通过Ribbon来实现负载均衡。

Ribbon 并不是 Spring Cloud 的一部分,而是 Spring Cloud Netflix 的一部分,而 Spring Cloud Netflix 最后一个版本是2.2.9.RELEASE,它支持 Spring Boot 2.x 系列。如果需要在 Spring Cloud 3.x 使用类似 Ribbon 的负载均衡功能,应该使用 Spring Cloud 提供的 Spring Cloud LoadBalancer,它是基于 Spring Framework 5, Project Reactor 和 Spring Boot 2.x 构建的,并且可以作为 Spring Cloud 的一部分使用。

由于本人教程项目所用Spring Cloud为3.0.0版本,将以spring-cloud-starter-loadbalancer为例。

5.1.LoadBalancer依赖导入

Spring Cloud Starter LoadBalancer是一个Spring Cloud的组件,它提供了负载均衡的能力,可以根据不同的负载均衡算法将请求分发到多个服务实例中。 LoadBalancer是基于Netflix Ribbon实现的,可以与服务注册中心(Eureka)结合使用,动态地从服务注册中心获取可用的服务实例列表,并根据配置的负载均衡策略进行请求分发。

spring-cloud-starter-netflix-eureka-client中,默认引入了spring-cloud-starter-loadbalancer组件的依赖。因为在使用Eureka作为服务注册中心的情况下,通常需要使用负载均衡的能力来分发请求到多个服务实例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.2.负载均衡配置

在消费端,新建负载均衡配置类。

@Configuration
public class LoadBalancerConfig {

    @Bean
    public ReactiveLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                       LoadBalancerClientFactory loadBalancerClientFactory) {

        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // 默认是轮询策略机制:RoundRobinLoadBalancer
        // 此处替换成随机轮询策略机制
        return new RandomLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class)
                ,name);
    }

}

5.3.启动类

@EnableFeignClients(basePackages = "org.ahao.project.remote.inf")
@SpringBootApplication
// 配置指定提供方服务的负载均衡器
@LoadBalancerClients({@LoadBalancerClient(name="provider", configuration = {LoadBalancerConfig.class})})
public class EurekaConsumerApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(EurekaConsumerApplication.class, args);
    }
}

5.4.重试机制配置

spring:
  application:
    name: consumer
  cloud:
    loadbalancer:
      retry:
        enabled: true
        retry-on-all-operations: false # 是否对所有操作都重试,默认为false
        max-retries-on-same-service-instance: 0 # 同一台实例的最大重试次数,不包括首次调用,默认为1次
        max-retries-on-next-service-instance: 2 # 切换实例进行重试的次数,默认值: 1
        retryable-status-codes: 400,401,403,404,500,502,504 # 对特定的HTTP响应码进行重试

常见的HTTP请求的状态码如下:

(1)2xx(成功)

这类状态码标识客户端的请求被成功接收、 理解并接受。 常见如200 (OK) 、 204 (NoContent) 。

(2)3xx(重定向)

这 类 状 态 码 标 识 请 求 发 起 端 / 请 求 代 理 要 做 出 进 一 步 的 动 作 来 完 成 请 求 , 常 见 如 301(MovedPermanently)、302(MovedTemprarily)。

(3)4xx(客户端错误)

这类状态码是在客户端出错时使用的,常见如400(BadRequest)、401(Unauthorized)、403(Forbidden)、404(NotFound)。

(4)5xx(服务器错误)

这类状态码表示服务器知道自己出错或者没有能力执行请求, 常见如500 (InternalServer Error) 、502(BadGateway)、504(GatewayTimeout)。

6.RPC调用保护

熔断器(Circuit Breaker)是一种用于改善分布式系统的稳定性和弹性的设计模式。在服务之间的通信中,当某个服务出现故障或异常时,及时地阻止请求该服务,从而避免级联故障的影响,提高系统的容错性和可用性。

6.1.失败回退

失败回退:当目标Provider实例发生故障时,RPC的失败回退会产生作用,返回一个后备的结果。

如何设置RPC调用的回退逻辑呢?有两种方式:

1)定义和使用一个Fallback回退处理类。

2)定义和使用一个FallbackFactory回退处理工厂类。

6.1.1.定义和使用一个 Fallback 回退处理类

为需要拥有回退机制的Feign客户端远程调用接口编写一个Fallback回退处理类,并将RPC失败后的回退逻辑编写在回退处理类中对应的实现方法中。

@Component
public class FeignProviderInterfaceFallback implements FeignProviderInterface {
    @Override
    public String test(String id) {
        return "执行方法失败返回默认值:"+0;
    }
}

@FeignClient注解中将fallback属性的值配置为上一步定义的Fallback回退处理类FeignProviderInterfaceFallback

@FeignClient(value = "provider", fallback = FeignProviderInterfaceFallback.class, path = "provider/feign/provider")
public interface FeignProviderInterface {

    /**
     * 注意此处与原本提供方接口地址/feign/provider/test/{id} 多了一个前缀/provider
     * 因为提供方服务配置了应用的上下文路径/provider
     *
     * @param id
     * @return
     */
    @GetMapping("/test/{id}")
    String test(@PathVariable("id") String id);

}
6.1.2.定义和使用一个FallbackFactory回退处理工厂类

定义一个简单的FallbackFactory回退处理工厂类,实现create方法,返回FeignProviderInterface实现类,相当于Fallback回退处理类。

@Component
public class FeignProviderInterfaceFallbackFactory implements FallbackFactory<FeignProviderInterface> {
    @Override
    public FeignProviderInterface create(Throwable cause) {
        return new FeignProviderInterface() {
            @Override
            public String test(String id) {
                return "执行方法失败返回默认值:"+0;
            }
        };
    }
}

@FeignClient注解上,将fallbackFactory属性的值配置为上一步定义的FeignProviderInterfaceFallbackFactory回退处理工厂类

@FeignClient(value = "provider", fallbackFactory = FeignProviderInterfaceFallbackFactory.class, path = "provider/feign/provider")
public interface FeignProviderInterface {

    /**
     * 注意此处与原本提供方接口地址/feign/provider/test/{id} 多了一个前缀/provider
     * 因为提供方服务配置了应用的上下文路径/provider
     *
     * @param id
     * @return
     */
    @GetMapping("/test/{id}")
    String test(@PathVariable("id") String id);

}
6.1.3.测试输出的内容

在这里插入图片描述

6.2.熔断

在微服务架构中根据业务拆分成的一个个的Provider微服务,由于网络原因或者自身的原因,服务并不能保证100%可用,为了保证微服务提供者高可用,单个Provider服务通常会多体部署。由于Provider与Provider之间的依赖性,故障或者不可用会沿请求调用链向上传递,会对整个系统造成瘫痪,这就是故障的“雪崩”效应。

引发雪崩效应的原因比较多,下面是常见的几种:

  • 硬件故障:如服务器宕机、机房断电、光纤被挖断等。

  • 流量激增:如异常流量、巨量请求瞬时涌入(如秒杀)等。

  • 缓存穿透:一般发生在系统重启所有缓存失效时,或者发生在短时间内大量缓存失效时,前端过来的大量请求没有命中缓存, 直击后端服务和数据库, 造成微服务提供者和数据库超负荷运行,引起整体瘫痪。

  • 程序BUG:如程序逻辑BUG导致内存泄漏等原因引发的整体瘫痪。

  • JVM卡顿:JVM的FullGC时间较长,极端的情况长达数十秒,这段时间内JVM不能提供任何服务。

为了解决雪崩效应, 业界提出了熔断器模型。 通过熔断器, 当一些非核心服务出现响应迟缓或者宕机等异常时,对服务进行降级并提供有损服务,以保证服务的柔性可用,避免引起雪崩效应。

6.2.1.熔断器

熔断器通常也叫作断路器, 其具体的工作机制: 统计最近RPC调用发生错误的次数, 然后根据统计值中的失败比例等信息决定是否允许后面的RPC调用继续或者快速地失败回退。熔断器的3种状态如下:

  • 关闭 (closed) : 熔断器关闭状态, 这也是熔断器的初始状态, 此状态下RPC调用正常放行。

  • 开启(open):失败比例到一定的阈值之后,熔断器进入开启状态。此状态下RPC将会快速失败,执行失败回退逻辑。

  • 半开启(half-open):在打开一定时间之后(睡眠窗口结束),熔断器进入半开启状态,小流量尝试进行RPC调用放行。如果尝试成功则熔断器变为关闭状态,RPC调用正常;如果尝试失败则熔断器变为开启状态,RPC调用快速失败。

熔断器状态之间相互转换的逻辑关系如图所示。

6.2.2.导入依赖
<!-- Spring Cloud Circuit Breaker 依赖 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
    <version>2.1.8</version>
</dependency>
6.2.3.相关配置
feign:
  circuitbreaker:
    enabled: true # 打开熔断开关
resilience4j:
  circuitbreaker:
    configs: # 熔断器配置
      default:
        failure-rate-threshold: 30 # 失败占比阈值
        sliding-window-type: COUNT_BASED # 滑动窗口类型
        sliding-window-size: 6 # 滑动窗口大小
        slow-call-duration-threshold: 2s # 当调用超过这个duration-threshold时,视为慢调用
        slow-call-rate-threshold: 10 # 当慢调用超过这个rate-threshold时,熔断器打开
        minimum-number-of-calls: 3  # 熔断器最小尝试次数
        automatic-transition-from-open-to-half-open-enabled: true  # 半开与全开的自动转换
        wait-duration-in-open-state: 5s   # 全开到半开的等待时间
        permitted-number-of-calls-in-half-open-state: 2 # 允许半开调用数
        record-exceptions: # 报错类型
            - java.lang.Exception
            - feign.FeignException
    instances: # 实例配置
      provider: # 实例名称
        base-config: default # 配置选择
6.2.4.测试结果

修改FeignProviderController内容。

@RestController
@RequestMapping("/consume")
public class FeignProviderController {

    @Autowired
    private FeignProviderInterface feignProviderInterface;

    @GetMapping("/{id}")
    @CircuitBreaker(name = "provider",fallbackMethod = "test")
    public String test(@PathVariable String id){
      	
        int i = Integer.parseInt(id);
        return feignProviderInterface.test(id);
    }

    // 熔断器:失败回退方法
    public String test(String id, Throwable throwable){
        return "系统繁忙,请稍后再试~:"+throwable.getMessage();
    }

}

输出非整型的id并多次调用,会出现以下结果。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1966651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 系统与SDK和JDK版本对照表

Android 系统与SDK和JDK版本对照表 传说中的兼容问题是指在高版本 SDK 平台开发的软件&#xff0c;可能在低版本 Android 系统中运行时出现各种问题。而低版本 SDK 开发的软件在高版本 Android 系统中运行时基本没有兼容问题的。 Android版本SDK/API版本JDK版本备注Android 14…

springboot宠物相亲平台-计算机毕业设计源码16285

目 录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2 开发环境及相关技术介绍 2.1 MySQL数据库的介绍 2.2 B/S架构的介绍 2.3 Java语言 2.4 SpringBoot框架 3 宠物相亲平台系统分析 3.1 可行性分析 3.1.1 技术可行性分析 3.1.2 经济…

unplugin-vue-components 插件配置 忽略 部分目录下的组件自动导入

背景 vue3 项目 为了省略 第三方库ui 组件 全局组件的注册代码&#xff0c;使用了 unplugin-vue-components 插件 原理 组件识别 在编译阶段&#xff0c;unplugin-vue-components 会扫描 Vue 单文件组件&#xff08;.vue 文件&#xff09;的模板部分&#xff0c;识别出所有使…

从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是小米,今天我们来聊一聊操作系统中的一个重要话题——进程间通信(Inter-Process Communication,简称IPC)。IPC是指在不同进程间传递数据…

01.docker安装、配置、常用命令、dockerfile、镜像上传下载和Harbor仓库搭建

1.docker安装 1.1移除旧版本 yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine1.2安装yum-utils获取yum-config-manager [rootlocalhost ~]# yum install -y yum-utils …

图论之最短路径问题(朴素Dijksra算法\堆优化版Dijksra算法\Bellman-Ford\SPFA)

朴素Dijskra算法 时间复杂度&#xff1a;,适用于稠密图&#xff0c;需要用邻接矩阵来存储。 算法描述 设起点为s,dist[v] 表示起点到v点的最短距离。 a)初始化 dist[v]INF(v!s),dist[s] 0 这里一共有n个点&#xff0c;第一个点(起点)初始化为0&#xff0c;其余都初始化为in…

COFFEE AI PARTNER -- 神奇的AI工具,相当我雇佣了一个AI员工,淘汰你的是会使用AI的人

COFFEE AI PARTNER介绍 COFFEE AI PARTNER是由 AI JAVA开发的一款生成式人工智能工具&#xff08;又名AI助手&#xff09;&#xff0c;尝试一下。 首先域名似乎正在备案中&#xff0c;企业邮箱似乎正在采购&#xff0c;目前服务地址是&#xff1a;COFFEE AI PARTNER-官网 官网…

基于JSP技术的教学质量评价系统

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a;JSP 数据库&#xff1a;MySQL 技术&#xff1a;JSPJavaBeans 工具&#xff1a;MyEclipse、Tomcat、Navicat 系统展示 首页 管理员功能模块 学生功…

前端面试:八股文系列(一)

更多详情&#xff1a;爱米的前端小笔记&#xff08;csdn~xitujuejin~zhiHu~Baidu~小红shu&#xff09;同步更新&#xff0c;等你来看&#xff01;都是利用下班时间整理的&#xff0c;整理不易&#xff0c;大家多多&#x1f44d;&#x1f49b;➕&#x1f914;哦&#xff01;你们…

大学新生入门编程的最佳路径

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

微服务架构三大利器:限流、降级与熔断

文章目录 前言一、限流&#xff08;Rate Limiting&#xff09;二、降级&#xff08;Degradation&#xff09;三、熔断&#xff08;Circuit Breaker&#xff09;四、三者关系总结 前言 限流、降级和熔断是分布式系统中常用的容错策略&#xff0c;它们各自承担着不同的角色&#…

5.Gateway-微服务统一网关

5.Gateway-微服务统一网关 1.为什么需要网关2.Spring Cloud Gateway2.1 引入依赖2.2 编写启动类2.3 配置路由规则2.4 路由断言&#xff08;Predicates&#xff09;2.5 过滤器&#xff08;Filters&#xff09;2.6 熔断机制 1.为什么需要网关 统一访问入口&#xff1a;在微服务架…

【微分方程——高数】

7.二阶常系数非齐次线性微分方程&#xff08;重点&#xff09; 8.欧拉方程&#xff08;重点&#xff09;

Prompt提示工程上手指南:基础原理及实践-Prompt个性知识库引导

前言 Prompt系列的第二期文章已经将所有的Prompt工程主流策略讲解完毕&#xff0c;共涉及到六种Prompt类别模型以及具体生产内容详解。再结合系列第一篇文章具体对Prompt工程的详细介绍&#xff0c;也就可以达到Prompt工程师的初步入门&#xff0c;现在如果掌握了这些基础技能…

缓存击穿

概念 缓存击穿问题也叫热点key问题&#xff0c;指的是一个被高并发访问并且缓存重建业务较为复杂的key突然失效了&#xff0c;大量的请求会到达数据库给数据库带来巨大的冲击。 常见解决方法有两种&#xff1a;互斥锁&#xff0c;逻辑过期。 优缺点 &#xff1a; 基于互斥锁的…

Python多进程:如何在不依赖Queue的情况下传递结果

随着数据的爆炸式增长&#xff0c;网络爬虫成为获取信息的强大工具。在爬取大量数据时&#xff0c;多进程技术可以显著提高效率。然而&#xff0c;如何在多进程中传递结果&#xff0c;而不依赖Queue&#xff0c;成为了一个值得探讨的问题。本文将以采集抖音短视频为案例&#x…

web框架:Django进阶(一)

文章目录 django进阶内容回顾1.模板1.1 寻找html模板顺序1.2 模板处理的本质1.3 常用语法1.4 内置函数1.5 自定义模板功能1.6 继承和母版1.7 模板的导入 2.django中间件2.1 原始方式2.2 MiddlewareMixin&#xff08;建议&#xff09;2.3 prcess_request的执行时&#xff0c;是否…

【系统设计】软件项目概要设计说明书(2024原件完整版)

1引言 1.1编写目的 1.2项目背景 1.3参考资料 2系统总体设计 2.1整体架构 2.2整体功能架构 2.3整体技术架构 2.4运行环境设计 2.5设计目标 3系统功能模块设计 3.1个人办公 3.2系统管理 4性能设计 4.1响应时间 4.2并发用户数 5接口设计 5.1接口设计原则 5.2接口实现方式 6运行设计…

qiankun 微前端 隔离子应用样式,解决 ant-design-vue 子应用样式污染问题(已落地)

样式冲突产生原因 先分析乾坤qiankun 构建之后&#xff0c;会根据你的配置 给每个子应用生成一个id&#xff0c; 当加载到对应子应用的时候&#xff0c;就把内容放到对应的id 标签里去&#xff0c; 这样能有效的隔离 js 代码&#xff0c;但是样式是加载在全局的 所以 当两个子…

【CSS】分享个纯CSS实现去除白底图效果的小技巧

效果 原理 技巧来源&#xff1a;Amazon的产品列表页 通过底色与遮罩层的透明度搭配实现&#xff0c;整体的"去白底"效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"view…