-
Notifications
You must be signed in to change notification settings - Fork 493
服务级熔断
本章节将介绍如何在 Spring Cloud
项目中使用 Spring Cloud Tencent Circuitbreaker
的服务级熔断。服务级熔断是指对整个微服务进行熔断控制。如果一个服务整体上出现了大量的错误请求,或者响应时间过长,那么熔断器会触发,将该服务的所有请求进行短路处理,直接返回错误结果或者执行预定义的降级处理。
请参考 安装北极星服务端
服务级熔断支持版本号大于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>1.10.0-2021.0.6</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 2021
及以上的版本,还需要添加如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</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,添加 @PolarisCircuitBreaker 注解
@Bean
@LoadBalanced
@PolarisCircuitBreaker
public RestTemplate restTemplateFallbackFromPolaris() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
@PolarisCircuitBreaker 包含两个参数:
- String 类型的 fallback 表示返回希望降级的 response body string
- PolarisCircuitBreakerFallback 类型的 fallbackClass 表示返回希望降级的具体 response,需要自定义实现 PolarisCircuitBreakerFallback#fallback() 方法,返回 PolarisCircuitBreakerHttpResponse
例如:
实现PolarisCircuitBreakerFallback接口
@Component
public class CustomFallback implements PolarisCircuitBreakerFallback {
@Override
public PolarisCircuitBreakerHttpResponse fallback() {
return new PolarisCircuitBreakerHttpResponse(
200,
new HashMap<String, String>() {{
put("Content-Type", "application/json");
}},
"{\"msg\": \"this is a fallback class\"}");
}
}
配置PolarisCircuitBreaker
的fallbackClass
参数:
@Bean
@LoadBalanced
@PolarisCircuitBreaker(fallbackClass = CustomFallback.class)
public RestTemplate restTemplateFallbackFromCode() {
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory("http://QuickstartCalleeService");
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(uriBuilderFactory);
return restTemplate;
}
注意,两个参数不能同时配置。
当 @PolarisCircuitBreaker 不配置任何参数时,会在熔断发生时,从 polaris server 拉取降级配置,进行降级,降级的 response body 会序列化成你在 RestTemplate 中配置的返回对象,请确保能正确的序列化。
发起 RestTemplate 调用
@RestController
@RequestMapping("/quickstart/caller/circuitBreak")
public class CircuitBreakerController {
@Autowired
private RestTemplate restTemplateFallbackFromPolaris;
@GetMapping("/rest/fallbackFromPolaris")
public ResponseEntity<String> circuitBreakRestTemplateFallbackFromPolaris() {
return restTemplateFallbackFromPolaris.getForEntity("/quickstart/callee/circuitBreak", String.class);
}
}
请参考我们的示例代码 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 都是对我们最大的支持
- 项目介绍
- 使用指南
- 最佳实践
- 开发文档
- 学习资料