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的远程调用。
注册中心、微服务提供者、远程客户端组件之间的关系大致如下图所示。
注册中心的主要功能如下:
- 服务注册表维护:这是注册中心的核心,用来记录各个微服务提供者实例的状态信息。注册中心提供Provider实例清单的查询和管理API,用于查询可用的Provider实例列表,管理Provider实例的上线和下线。
- 服务健康检查: 注册中心使用一定机制定时检测已注册的Provider实例, 如发现某实例长时间无法访问,就会从服务注册表中移除该实例。
微服务提供者的主要功能如下:
- 服务注册:服务注册是指Provider微服务实例在启动时将自己的信息注册到注册中心上的过程。
- 心跳续约:Provider实例会定时向服务注册中心提供“心跳”,以表明自己还处于可用的状态。当一个Provider实例停止心跳一段时间后,注册中心会认为该服务实例不可用了,就会将该服务实例从服务注册列表中剔除。 如果被剔除的Provider实例过一段时间后继续向注册中心提供心跳,那么服务注册中心会将该Provider实例重新加入服务注册表中。
- 健康状况查询: Provider实例能提供健康状况查看的API, 注册中心或者其他的微服务Provider能够获取其健康状况。
微服务提供者的服务注册和心跳续约一般都会通过注册中心客户端组件来完成。 注册中心客户端组件还有如下功能:
- 服务发现:从注册中心查询可用Provider实例清单。
- 实例缓存: 将从注册中心查询到的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
外,应用健康状态还有DOWN
、OUT_OF_SERVICE
、UNKONWN
等其他取值,不过只有状态为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请求,该方法的返回值是一个ResponseEntity
。ResponseEntity
是Spring对HTTP响应的封装,包括了几个重要的元素,如响应码、contentType
、contentLength
、响应消息体等。
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并多次调用,会出现以下结果。