Skip to content

服务级熔断

Haotian Zhang edited this page Jul 2, 2024 · 12 revisions

目录

本章节将介绍如何在 Spring Cloud 项目中使用 Spring Cloud Tencent Circuitbreaker 的服务级熔断。服务级熔断是指对整个微服务进行熔断控制。如果一个服务整体上出现了大量的错误请求,或者响应时间过长,那么熔断器会触发,将该服务的所有请求进行短路处理,直接返回错误结果或者执行预定义的降级处理。

第一步:引入 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>1.10.0-2021.0.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

1. 主调方和被调方都引入服务注册与发现依赖

因为熔断能力依赖服务发现能力,所以需要主调方和被调方都引入服务注册与发现依赖。

1.1 引入 Spring Cloud Tencent Discovery Starter

方式一:只引入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>

2. 主调方引入熔断依赖

方式一:只引入 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 四种组件的熔断,并会自动拉取你在北极星上为被调服务配置的熔断规则进行熔断。具体配置如下:

Feign 支持

可以查看代码中的 quickstart-caller-service中的CircuitBreakerController.java,以下对代码重点做解释:

添加 Feign 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

添加 Feign 配置文件

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

当 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();
	}


}

RestTemplate 支持

请参考我们的示例代码 quickstart-caller-service中的CircuitBreakerController.java,以下对代码重点做解释:

添加 RestTemplate 配置文件

spring:
  application:
    name: polaris-circuitbreaker-resttemplate-example
  cloud:
    polaris:
      address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
      namespace: default
      enabled: true
      loadbalancer:
        enabled: true
      circuitbreaker:
        enabled: true

设置 RestTemplate 熔断方法

设置 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\"}");
	}
}

配置PolarisCircuitBreakerfallbackClass参数:

@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);
	}

}

WebClient 支持

请参考我们的示例代码 quickstart-caller-service,以下对代码重点做解释:

添加 WebFlux 依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

设置 WebClient 配置文件

spring:
  application:
    name: polaris-circuitbreaker-webclient-example
  cloud:
    polaris:
      address: grpc://${修改为第一步部署的 Polaris 服务地址}:8091
      namespace: default
      enabled: true
      loadbalancer:
        enabled: true
      circuitbreaker:
        enabled: true

设置 WebClient 熔断方法

设置 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"))
				);
	}

}

Spring Cloud Gateway 支持

可以查看代码中的quickstart-gateway-service ,以下对代码重点做解释:

添加 Spring Cloud Gateway 依赖

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

设置 Spring Cloud Gateway 配置文件

以 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

设置 Spring Cloud Gateway 熔断方法

设置熔断降级的转发路由方法

@RestController
public class FallbackController {

	@GetMapping("/polaris-fallback")
	Mono<String> getFallback() {
		return Mono.just("fallback: trigger the refuse for service caller.");
	}
}

第四步:验证

启动应用并在北极星控制台设置被调服务的服务级熔断规则:

image

为了验证熔断能力,被调端至少启动两个实例,一个返回成功,一个返回失败。在示例代码quickstart-examplequickstart-callee-service-aquickstart-callee-service-b分别作为QuickstartCalleeService的两个实例A和B。 quickstart-caller-service作为主调方调用QuickstartCalleeService/quickstart/callee/circuitBreak接口。实例A将返回 200,实例B将返回 502。

测试主调方向被调方发起服务调用,前几个请求会出现往有问题的服务发起调用,当问题数达到你在北极星控制台配置的熔断阈值时,即会触发熔断,主调方不再发起调用,直接返回熔断降级方法。

Clone this wiki locally