Skip to content

服务熔断

Haotian Zhang edited this page Dec 16, 2024 · 1 revision

目录

模块简介

故障实例熔断是常见的一种容错保护机制。Spring Cloud Tencent CircuitBreaker 结合 Polaris 的熔断能力提供了标准的熔断实现,并提供服务级、接口级、节点级三种级别的熔断能力,你可以根据需求组合搭配,来实现期望的熔断效果。

节点级熔断

节点级熔断针对的是微服务实例(节点)。在一个微服务通常有多个实例运行的环境中,如果某个实例出现错误率高或故障等问题,故障实例熔断能实现主调方对该实例的迅速自动屏蔽,并启动定时任务对熔断实例进行探活。在达到恢复条件后对其进行半开恢复。在半开恢复后,释放少量请求去进行真实业务探测。并根据真实业务探测结果去判断是否完全恢复正常。

如下图所示,假设某个服务下存在3个服务实例,当被调端 Instance3 出现异常时,会触发Instance3熔断,主调端会自动的把请求只打到 Instance1Instance2,通过这种方式保证主调端能够正常的调用服务。

image

服务级熔断

如果一个服务整体上出现了大量的错误请求,或者响应时间过长,那么熔断器会触发,将该服务的所有请求进行短路处理,直接返回错误结果或者执行预定义的降级处理。

接口级熔断

相比于服务级熔断,接口级熔断提供对服务中某个具体接口的熔断控制。如果某个接口出现了大量的错误请求或者响应时间过长,熔断器会触发,短路对该接口的请求,直接返回失败或者执行降级逻辑。与此同时其他接口不受影响,依然可以正常调用。接口级熔断适用于某个接口出现问题而其他接口正常的场景。

熔断策略

  • 故障比例熔断:当服务实例在上一个时间窗(默认1分钟)内,通过的请求量达到或超过最小请求阈值(默认10个),且错误率达到或超过故障比率阈值(默认50%),实例会进入隔离状态。故障比率的阈值范围是 [0.0, 1.0],代表 0% - 100%
  • 连续故障熔断:当实例在上一个时间窗(默认1分钟)内,连续失败的请求数达到或者超过连续故障阈值(默认10个),实例会进入隔离状态。
  • 熔断隔离时间:默认隔离30s,支持可配置。

具体可参考 Polaris 熔断降级

快速入门

第一步:引入 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>

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>

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

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

}

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