1. Overview
1.概述
In this tutorial, we’ll introduce the Spring Cloud Circuit Breaker project and learn how we can make use of it.
在本教程中,我们将介绍Spring Cloud Circuit Breaker项目,并学习我们如何利用它。
First, we’re going to see what the Spring Cloud Circuit Breaker offers in addition to existing circuit breaker implementations. Next, we’ll learn how to use the Spring Boot auto-configuration mechanism to integrate one or more circuit breakers into our application.
首先,我们要看看Spring Cloud Circuit Breaker在现有的断路器实现之外还提供了哪些功能。接下来,我们将学习如何使用Spring Boot自动配置机制,将一个或多个断路器集成到我们的应用程序中。
Note that we’ve got more information about what a circuit breaker is and how they work in Introduction to Hystrix, Spring Cloud Netflix Hystrix, and Guide to Resilience4j.
请注意,我们在Introduction to Hystrix、Spring Cloud Netflix Hystrix和Guide to Resilience4j中有关于什么是断路器以及它们如何工作的详细信息。
2. Spring Cloud Circuit Breaker
2.春云断路器
Until recently, Spring Cloud only provided us one way to add circuit breakers in our applications. This was through the use of Netflix Hystrix as part of the Spring Cloud Netflix project.
直到最近,Spring Cloud只为我们提供了一种在应用程序中添加断路器的方法。这就是通过使用Netflix Hystrix作为Spring Cloud Netflix项目的一部分。
The Spring Cloud Netflix project is really just an annotation-based wrapper library around Hystrix. Therefore, these two libraries are tightly-coupled. This means we can’t switch to another circuit breaker implementation without changing the application.
Spring Cloud Netflix项目实际上只是Hystrix周围的一个基于注释的包装库。因此,这两个库是紧密耦合的。这意味着我们不能在不改变应用的情况下切换到另一个断路器的实现。
The Spring Cloud Circuit Breaker project solves this. It provides an abstraction layer across different circuit breaker implementations. It’s a pluggable architecture. So, we can code against the provided abstraction/interface and switch to another implementation based on our needs.
Spring Cloud Circuit Breaker项目解决了这个问题。它提供了一个跨越不同断路器实现的抽象层。它是一个可插拔的架构。因此,我们可以根据所提供的抽象/接口进行编码,并根据我们的需要切换到另一个实现。
For our examples, we’ll focus only on the Resilience4J implementation. However, these techniques can be used for other plugins.
在我们的例子中,我们将只关注Resilience4J的实现。然而,这些技术也可以用于其他插件。
3. Auto Configuration
3.自动配置
In order to use a specific circuit breaker implementations in our application, we need to add the appropriate Spring starter. In our case, let’s use spring-cloud-starter-circuitbreaker-resilience4j:
为了在我们的应用程序中使用特定的断路器实现,我们需要添加适当的Spring启动器。在我们的案例中,让我们使用spring-cloud-starter-circuitbreaker-resilience4j。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
<version>1.0.2.RELEASE</version>
</dependency>
The auto-configuration mechanism configures the necessary circuit breaker beans if it sees one of the starters in the classpath.
自动配置机制如果看到classpath中的启动器之一,就会配置必要的断路器Bean。
If we wanted to disable the Resilience4J auto-configuration, we could set the spring.cloud.circuitbreaker.resilience4j.enabled property to false.
如果我们想禁用Resilience4J的自动配置,我们可以将spring.cloud.circuitbreaker.resilience4j.enabled属性设为false。
4. A Simple Circuit Breaker Example
4.一个简单的断路器实例
Let’s create a web application using Spring Boot to allow us to explore how the Spring Cloud Circuit Breaker library works.
让我们使用Spring Boot创建一个Web应用程序,让我们探索Spring Cloud Circuit Breaker库是如何工作的。
We’ll build a simple web service returning a list of albums. Let’s suppose the raw list is provided by a third-party service. For simplicity, we’ll use an external dummy API provided by Jsonplaceholder to retrieve the list:
我们将建立一个简单的网络服务,返回一个专辑列表。让我们假设原始列表是由第三方服务提供的。为了简单起见,我们将使用一个由Jsonplaceholder提供的外部虚拟API来检索该列表。
https://jsonplaceholder.typicode.com/albums
4.1. Create a Circuit Breaker
4.1.创建一个断路器
Let’s create our first circuit breaker. We’ll start by injecting an instance of the CircuitBreakerFactory bean:
让我们来创建我们的第一个断路器。我们将首先注入一个CircuitBreakerFactory Bean的实例。
@Service
public class AlbumService {
@Autowired
private CircuitBreakerFactory circuitBreakerFactory;
//...
}
Now, we can easily create a circuit breaker using the CircuitBreakerFactory#create method. It takes the circuit breaker identifier as an argument:
现在,我们可以使用CircuitBreakerFactory#create方法轻松创建一个断路器。它需要断路器的标识符作为参数。
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
4.2. Wrap a Task in a Circuit Breaker
4.2.将任务包裹在断路器中
In order to wrap and run a task protected by the circuit breaker, we need to call the run method which takes a Supplier as an argument.
为了包裹和运行一个受断路器保护的任务,我们需要调用run方法,该方法需要一个Supplier作为参数。
public String getAlbumList() {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
String url = "https://jsonplaceholder.typicode.com/albums";
return circuitBreaker.run(() -> restTemplate.getForObject(url, String.class));
}
The circuit breaker runs our method for us and provides fault tolerance.
断路器为我们运行我们的方法并提供容错功能。
Sometimes, our external service could take too long to respond, throw an unexpected exception or the external service or host does not exist. In that case, we can provide a fallback as a second argument to the run method:
有时,我们的外部服务可能需要太长时间来响应,抛出一个意外的异常,或者外部服务或主机不存在。在这种情况下,我们可以提供一个回退作为run方法的第二个参数。
public String getAlbumList() {
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
String url = "http://localhost:1234/not-real";
return circuitBreaker.run(() -> restTemplate.getForObject(url, String.class),
throwable -> getDefaultAlbumList());
}
The lambda for the fallback receives the Throwable as an input, describing the error. This means we can provide different fallback results to the caller, based on the type of exception that triggered the fallback.
回退的lambda接收Throwable作为输入,描述了错误。这意味着我们可以根据触发回退的异常类型,向调用者提供不同的回退结果。
In this case, we won’t take the exception into account. We’ll just return a cached list of albums.
在这种情况下,我们不会考虑到这个例外。我们将只是返回一个缓存的专辑列表。
If the external call ends with an exception and no fallback is provided, a NoFallbackAvailableException is thrown by Spring.
如果外部调用以异常结束,并且没有提供回退,Spring会抛出一个NoFallbackAvailableException。
4.3. Build a Controller
4.3.建立一个控制器
Now, let’s finish our example and create a simple controller that calls the service methods and presents the results through a browser:
现在,让我们完成我们的例子,创建一个简单的控制器,调用服务方法并通过浏览器呈现结果。
@RestController
public class Controller {
@Autowired
private Service service;
@GetMapping("/albums")
public String albums() {
return service.getAlbumList();
}
}
Finally, let’s call the REST service and see the results:
最后,让我们调用REST服务,看看结果。
[GET] http://localhost:8080/albums
5. Global Custom Configuration
5.全局自定义配置
Usually, the default configuration is not enough. For this reason, we need to create circuit breakers with custom configurations based on our use cases.
通常情况下,默认配置是不够的。出于这个原因,我们需要根据我们的用例创建具有自定义配置的断路器。
In order to override the default configuration, we need to specify our own beans and properties in a @Configuration class.
为了覆盖默认配置,我们需要在@Configuration类中指定我们自己的bean和属性。
Here, we’re going to define a global configuration for all circuit breakers. For this reason, we need to define a Customizer<CircuitBreakerFactory> bean. So let’s use the Resilience4JCircuitBreakerFactory implementation.
在这里,我们要为所有断路器定义一个全局配置。为此,我们需要定义一个Customizer<CircuitBreakerFactory> bean。因此,让我们使用Resilience4JCircuitBreakerFactory实现。
First, we’ll define circuit breaker and time limiter configuration classes as per the Resilience4j tutorial:
首先,我们将按照Resilience4j教程定义断路器和时间限制器配置类。
CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.slidingWindowSize(2)
.build();
TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(4))
.build();
Next, let’s embed the configuration in a Customizer bean by using the Resilience4JCircuitBreakerFactory.configureDefault method:
接下来,让我们通过使用Resilience4JCircuitBreakerFactory.configureDefault方法将配置嵌入Customizerbean中。
@Configuration
public class Resilience4JConfiguration {
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> globalCustomConfiguration() {
// the circuitBreakerConfig and timeLimiterConfig objects
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.timeLimiterConfig(timeLimiterConfig)
.circuitBreakerConfig(circuitBreakerConfig)
.build());
}
}
6. Specific Custom Configuration
6.具体的自定义配置
Of course, we can have multiple circuit breakers in our application. Therefore, in some cases, we need a specific configuration for every circuit breaker.
当然,我们的应用中可以有多个断路器。因此,在某些情况下,我们需要为每个断路器提供特定的配置。
Similarly, we can define one or more Customizer beans. Then, we can provide a different configuration for each one by using the Resilience4JCircuitBreakerFactory.configure method:
同样地,我们可以定义一个或多个Customizer Bean。然后,我们可以通过使用Resilience4JCircuitBreakerFactory.configure方法为每个人提供不同的配置。
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> specificCustomConfiguration1() {
// the circuitBreakerConfig and timeLimiterConfig objects
return factory -> factory.configure(builder -> builder.circuitBreakerConfig(circuitBreakerConfig)
.timeLimiterConfig(timeLimiterConfig).build(), "circuitBreaker");
}
Here we provide a second parameter, the id of the circuit breaker we’re configuring.
这里我们提供第二个参数,即我们要配置的断路器的ID。
We can also set up multiple circuit breakers with the same configuration by providing a list of circuit breaker ids to the same method:
我们还可以通过向同一方法提供一个断路器ID列表来设置多个具有相同配置的断路器。
@Bean
public Customizer<Resilience4JCircuitBreakerFactory> specificCustomConfiguration2() {
// the circuitBreakerConfig and timeLimiterConfig objects
return factory -> factory.configure(builder -> builder.circuitBreakerConfig(circuitBreakerConfig)
.timeLimiterConfig(timeLimiterConfig).build(),
"circuitBreaker1", "circuitBreaker2", "circuitBreaker3");
}
7. Alternative Implementations
7.替代实施方案
We’ve seen how to use the Resilience4j implementation to create one or more circuit breakers with Spring Cloud Circuit Breaker.
我们已经看到如何使用Resilience4j实现,用Spring Cloud Circuit Breaker创建一个或多个断路器。
However, there are other implementations supported by Spring Cloud Circuit Breaker that we can leverage in our application:
然而,Spring Cloud Circuit Breaker支持的其他实现,我们可以在我们的应用程序中加以利用。
It’s worth mentioning that we can mix and match different circuit breaker implementations in our application. We’re not just limited to one library.
值得一提的是,我们可以在应用中混合和匹配不同的断路器实现。我们并不仅仅局限于一个库。
The above libraries have more capabilities than we’ve explored here. However, Spring Cloud Circuit Breaker is an abstraction over only the circuit breaker part. For example, Resilience4j also provides other modules like RateLimiter, Bulkhead, Retry in addition to the CircuitBreaker and TimeLimiter modules used in this article.
上述库的功能比我们在这里探讨的要多。然而,Spring Cloud Circuit Breaker只是对断路器部分的抽象。例如,Resilience4j还提供了其他模块,如RateLimiter、Bulkhead、Retry,此外还有本文使用的CircuitBreaker和TimeLimiter模块。
8. Conclusion
8.结语
In this article, we discovered the Spring Cloud Circuit Breaker project.
在这篇文章中,我们发现了Spring Cloud Circuit Breaker项目。
First, we learned what the Spring Cloud Circuit Breaker is, and how it allows us to add circuit breakers to our application.
首先,我们了解了什么是Spring Cloud Circuit Breaker,以及它如何让我们在应用程序中添加断路器。
Next, we leveraged the Spring Boot auto-configuration mechanism in order to show how to define and integrate circuit breakers. Also, we demonstrated how the Spring Cloud Circuit Breaker works through a simple REST service.
接下来,我们利用Spring Boot的自动配置机制,以展示如何定义和整合断路器。另外,我们还演示了Spring Cloud断路器是如何通过一个简单的REST服务工作的。
Finally, we learned to configure all circuit breakers together, as well as individually.
最后,我们学会了将所有断路器配置在一起,以及单独配置。
As always, the source code for this tutorial is available over on GitHub.
一如既往,本教程的源代码可在GitHub上获得。