-
Notifications
You must be signed in to change notification settings - Fork 495
服务熔断
故障实例熔断是常见的一种容错保护机制。Spring Cloud Tencent CircuitBreaker 结合 Polaris 的熔断能力提供了标准的熔断实现,并提供服务级、接口级、节点级三种级别的熔断能力,你可以根据需求组合搭配,来实现期望的熔断效果。
节点级熔断针对的是微服务实例(节点)。在一个微服务通常有多个实例运行的环境中,如果某个实例出现错误率高或故障等问题,故障实例熔断能实现主调方对该实例的迅速自动屏蔽,并启动定时任务对熔断实例进行探活。在达到恢复条件后对其进行半开恢复。在半开恢复后,释放少量请求去进行真实业务探测。并根据真实业务探测结果去判断是否完全恢复正常。
如下图所示,假设某个服务下存在3个服务实例,当被调端 Instance3
出现异常时,会触发Instance3
熔断,主调端会自动的把请求只打到 Instance1
,Instance2
,通过这种方式保证主调端能够正常的调用服务。
如果一个服务整体上出现了大量的错误请求,或者响应时间过长,那么熔断器会触发,将该服务的所有请求进行短路处理,直接返回错误结果或者执行预定义的降级处理。
相比于服务级熔断,接口级熔断提供对服务中某个具体接口的熔断控制。如果某个接口出现了大量的错误请求或者响应时间过长,熔断器会触发,短路对该接口的请求,直接返回失败或者执行降级逻辑。与此同时其他接口不受影响,依然可以正常调用。接口级熔断适用于某个接口出现问题而其他接口正常的场景。
- 故障比例熔断:当服务实例在上一个时间窗(默认1分钟)内,通过的请求量达到或超过最小请求阈值(默认10个),且错误率达到或超过故障比率阈值(默认
50%
),实例会进入隔离状态。故障比率的阈值范围是[0.0, 1.0]
,代表0% - 100%
。 - 连续故障熔断:当实例在上一个时间窗(默认1分钟)内,连续失败的请求数达到或者超过连续故障阈值(默认10个),实例会进入隔离状态。
- 熔断隔离时间:默认隔离
30s
,支持可配置。
具体可参考 Polaris 熔断降级
请参考 安装北极星服务端
服务级熔断支持版本号大于1.10.0
的 Spring Cloud Tencent 版本。
参考 Spring Cloud Tencent 版本管理 文档获取最新的版本号,引入 Spring Cloud Tencent Bom
。
注意: Spring Cloud 、 Spring Boot 、 Spring Framework 之间有严格的版本对应关系,在 Spring Cloud Tencent 版本管理 文档中有详细罗列版本兼容性关系。请您在引入 Spring Cloud Tencent 版本时,根据项目 Spring Boot 和 Spring Framework 的版本,选择合适的 Spring Cloud Tencent 版本。
例如:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId>
<version>2.0.0.0-2022.0.5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
因为熔断能力依赖服务发现能力,所以需要主调方和被调方都引入服务注册与发现依赖。
方式一:只引入spring-cloud-starter-tencent-polaris-discovery
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
</dependency>
方式二:通过 spring-cloud-starter-tencent-all
引入 sct 所有 starters
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-all</artifactId>
</dependency>
方式一:只引入 spring-cloud-starter-tencent-polaris-circuitbreaker
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
</dependency>
方式二:通过 spring-cloud-starter-tencent-all
引入 sct 所有 starters
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-all</artifactId>
</dependency>
Spring Cloud Tencent 支持 Feign、RestTemplate、WebClient、Spring Cloud Gateway 四种组件的熔断,并会自动拉取你在北极星上为被调服务配置的熔断规则进行熔断。具体配置如下:
可以查看代码中的 quickstart-caller-service中的CircuitBreakerController.java,以下对代码重点做解释:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Spring Cloud 2020/2021 版本
spring:
application:
name: QuickstartCallerService
cloud:
polaris:
address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
namespace: default
enabled: true
loadbalancer:
enabled: true
circuitbreaker:
enabled: true
feign:
circuitbreaker:
enabled: true
Spring Cloud 2022 及以上版本
spring:
application:
name: QuickstartCallerService
cloud:
openfeign:
circuitbreaker:
enabled: true
polaris:
address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
namespace: default
enabled: true
loadbalancer:
enabled: true
circuitbreaker:
enabled: true
声明 Feign 调用
当 Feign fallback 不配置时,会在熔断发生时,从 polaris server 拉取降级配置,进行降级,降级的 response body 会序列化成你在 Feign 中配置的返回对象,请确保能正确的序列化。
// 当 Feign fallback 不配置时,会在熔断发生时,从 polaris server 拉取降级配置,进行降级,
// 降级的 response body 会序列化成你在 Feign 中配置的返回对象,请确保能正确的序列化。
@FeignClient(name = "QuickstartCalleeService", contextId = "fallback-from-code", fallback = CircuitBreakerQuickstartCalleeServiceFallback.class)
public interface CircuitBreakerQuickstartCalleeServiceWithFallback {
/**
* Check circuit break.
*
* @return circuit break info
*/
@GetMapping("/quickstart/callee/circuitBreak")
String circuitBreak();
}
声明本地 Feign 熔断方法(可选)
@Component
public class CircuitBreakerQuickstartCalleeServiceFallback implements CircuitBreakerQuickstartCalleeServiceWithFallback {
@Override
public String circuitBreak() {
return "fallback: trigger the refuse for service callee.";
}
}
发起 Feign 调用
@RestController
@RequestMapping("/quickstart/caller/circuitBreak")
public class CircuitBreakerController {
@Autowired
private CircuitBreakerQuickstartCalleeServiceWithFallback circuitBreakerQuickstartCalleeServiceWithFallback;
/**
* Feign circuit breaker with fallback from Polaris.
* @return circuit breaker information of callee
*/
@GetMapping("/feign/fallbackFromCode")
public String circuitBreakFeignFallbackFromCode() {
return circuitBreakerQuickstartCalleeServiceWithFallback.circuitBreak();
}
}
请参考我们的示例代码 quickstart-caller-service中的CircuitBreakerController.java,以下对代码重点做解释:
spring:
application:
name: polaris-circuitbreaker-resttemplate-example
cloud:
polaris:
address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
namespace: default
enabled: true
loadbalancer:
enabled: true
circuitbreaker:
enabled: true
设置 RestTemplate bean
@Bean
@LoadBalanced
public RestTemplate calleeRestTemplate() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
发起 RestTemplate 调用
@RestController
@RequestMapping("/quickstart/caller/circuitBreak")
public class CircuitBreakerController {
@Autowired
@Qualifier("calleeRestTemplate")
private RestTemplate calleeRestTemplate;
@GetMapping("/rest/fallbackFromPolaris")
public ResponseEntity<String> circuitBreakRestTemplateFallbackFromPolaris() {
try {
return calleeRestTemplate.getForEntity("/quickstart/callee/circuitBreak", String.class);
}
catch (HttpClientErrorException | HttpServerErrorException httpClientErrorException) {
return new ResponseEntity<>(httpClientErrorException.getResponseBodyAsString(), httpClientErrorException.getStatusCode());
}
}
}
请参考我们的示例代码 quickstart-caller-service,以下对代码重点做解释:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
spring:
application:
name: polaris-circuitbreaker-webclient-example
cloud:
polaris:
address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
namespace: default
enabled: true
loadbalancer:
enabled: true
circuitbreaker:
enabled: true
设置 WebClient bean
@LoadBalanced
@Bean
WebClient.Builder webClientBuilder() {
return WebClient.builder().baseUrl("http://QuickstartCalleeService");
}
发起 WebClient 调用
@RestController
@RequestMapping("/quickstart/caller/circuitBreak")
public class CircuitBreakerController {
@Autowired
private ReactiveCircuitBreakerFactory reactiveCircuitBreakerFactory;
@Autowired
private WebClient.Builder webClientBuilder;
/**
* Get information of callee.
* @return information of callee
*/
@GetMapping("/webclient")
public Mono<String> webclient() {
return webClientBuilder
.build()
.get()
.uri("/quickstart/callee/circuitBreak")
.retrieve()
.bodyToMono(String.class)
.transform(it ->
reactiveCircuitBreakerFactory
.create("QuickstartCalleeService")
.run(it, throwable -> Mono.just("fallback: trigger the refuse for service callee"))
);
}
}
可以查看代码中的quickstart-gateway-service ,以下对代码重点做解释:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
以 gateway.discovery.locator 形式配置
spring:
application:
name: GatewayScgService
cloud:
polaris:
address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
namespace: default
enabled: true
gateway:
discovery:
locator:
enabled: true
'predicates[0]':
name: Path
args:
patterns: '''/'' + serviceId + ''/**'''
'filters[0]':
name: RewritePath
args:
regexp: '''/'' + serviceId + ''/(?<remaining>.*)'''
replacement: '''/$\{remaining}'''
'filters[1]':
# 配置熔断 Filter
name: CircuitBreaker
args:
# statusCodes,可选参数,配置熔断的匹配返回码,缺省时会自动识别 "5**" 为错误,可以为"4**,5**"的形式,也可以为具体的返回码
statusCodes: '''404,5**'''
# fallbackUri,可选参数,配置熔断降级的转发路由方法,缺省时会在熔断触发后拉取 plaris server 配置的降级作为 response
fallbackUri: '''forward:/polaris-fallback'''
以普通路由形式配置形式配置
spring:
application:
name: GatewayScgService
cloud:
polaris:
address: grpc://119.91.66.223:8091
namespace: default
enabled: true
gateway:
routes:
- id: QuickstartCalleeService
uri: lb://QuickstartCalleeService
predicates:
- Path=/QuickstartCalleeService/**
filters:
- StripPrefix=1
# 配置熔断 Filter
- name: CircuitBreaker
args:
# statusCodes,可选参数,配置熔断的匹配返回码,缺省时会自动识别 "5**" 为错误,可以为"4**,5**"的形式,也可以为具体的返回码
statusCodes: 404,5**
# fallbackUri,可选参数,配置熔断降级的转发路由方法,缺省时会在熔断触发后拉取 plaris server 配置的降级作为 response
fallbackUri: forward:/polaris-fallback
设置熔断降级的转发路由方法
@RestController
public class FallbackController {
@GetMapping("/polaris-fallback")
Mono<String> getFallback() {
return Mono.just("fallback: trigger the refuse for service caller.");
}
}
启动应用并在北极星控制台设置被调服务的服务级熔断规则:
为了验证熔断能力,被调端至少启动两个实例,一个返回成功,一个返回失败。在示例代码quickstart-example,quickstart-callee-service-a和quickstart-callee-service-b分别作为QuickstartCalleeService
的两个实例A和B。
quickstart-caller-service作为主调方调用QuickstartCalleeService
的/quickstart/callee/circuitBreak
接口。实例A将返回 200,实例B将返回 502。
测试主调方向被调方发起服务调用,前几个请求会出现往有问题的服务发起调用,当问题数达到你在北极星控制台配置的熔断阈值时,即会触发熔断,主调方不再发起调用,直接返回熔断降级方法。
- 您在使用过程中遇到任何问题,请提 Issue 或者加入我们的开发者群告诉我们,我们会在第一时间反馈
- Spring Cloud Tencent 社区期待您的加入,一个 Star、PR 都是对我们最大的支持
- 项目介绍
- 使用指南
- 最佳实践
- 开发文档
- 学习资料