docs: Translation for zh (#1805)

* add state and callback pattern

* add command and template-method pattern

* add iterator pattern

* add bridege and DI pattern

* fix issue #1600

* add converter,proxy,visitor pattern

* add caching,composite,delegation,dirty-flag,interpreter patterns

* add dao and producer-consumer

* add dto and provate class data pattern

* fix #1646 png path problems

* fix #1646 composite png path case problem

* add abstract document pattern and version-number pattern

* add ambassador pattern

* add acyclic-visitor and api-gateway pattern

* add abstract-factory pattern

* add active-object pattern

* add aggregator-microservices and arrange-act-assert pattern

* update async-method-invocation pattern

* add balking and business-delegate pattern

* add bytecode and circuit-break pattern

* update arrange/act/assert pattern problems

* add csch pattern

* add language code, correct pic path

* #1805 update permalink

Co-authored-by: Subhrodip Mohanta <subhrodipmohanta@gmail.com>
Co-authored-by: Mike <admin@xiaod.info>
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
Mike Liu
2021-08-01 22:55:54 +08:00
committed by GitHub
parent d36efdbc7c
commit c5a4068e84
50 changed files with 595 additions and 221 deletions

View File

@ -4,39 +4,45 @@ title: Circuit Breaker
folder: circuit-breaker
permalink: /patterns/circuit-breaker/
categories: Behavioral
language: zh
tags:
- Performance
- Decoupling
- Cloud distributed
---
## 含义
## 意图
以这样的方式(译者:指断路器方式)处理昂贵的远程服务调用,可以防止单个服务/组件的故障导致整个应用程序崩溃,同时我们可以尽快地进行服务重连
以这样一种方式处理昂贵的远程服务调用,单个服务/组件的故障不会导致整个应用程序宕机,我们可以尽快重新连接到服务
## 解释
实世界
实世界例
> 设想一下,一个网络应用程序既有本地文件/图像,又有用于获取数据的远程服务。这些远程服务可能在某些时候是健康的、有反应的,也可能在某些时候由于各种原因而变得缓慢和无应。因此,如果其中一个远程服务速度慢或不能成功响应,我们的应用程序将尝试使用多个线程/进程从远程服务获取响应,很快所有的线程/进程都会挂起(也称为线程饥饿 thread starvation),从而导致我们整个 Web 应用程序崩溃。我们应该能够检测到这种情况并向用户显示一个适当的息,以便用户可以探索应用程序的其他部分,而不受远程服务故障影响同时,其他正常工作的服务应保持运作,不受这次故障的影响。
> 想象一个 Web 应用程序,它同时具有用于获取数据的本地文件/图像和远程服务。 这些远程服务有时可能健康且响应迅速,或者由于各种原因可能在某 个时间点变得缓慢和无应。因此,如果其中一个远程服务缓慢或未成功响应,我们的应用程序将尝试使用多个线程/进程从远程服务获取响应,很快它们都会挂起(也称为 [线程饥饿][thread starvation](https://en.wikipedia.org/wiki/Starvation_(computer_science)))导致我们整个 Web 应用程序崩溃。我们应该能够检测到这种情况并向用户显示适当的息,以便他/她可以探索不受远程服务故障影响的应用程序的其他部分。 同时,其他正常工作的服务应保持正常运行,不受故障的影响。
>
简而言之
通俗地说
> 断路器允许优雅地处理失败的远程服务。当我们应用程序的所有部分高度解耦时,这种方式的效果会很好,一个组件的失败并不会导致其他部分停止工作。
> 断路器允许优雅地处理失败的远程服务。当我们应用程序的所有部分彼此高度解耦时,它特别有用,一个组件的故障并不意味着其他部分停止工作。
维基百科的解释
维基百科
> 断路器是现代软件开发中使用的一种设计模式。它用于检测故障并封装防止故障不断复发的逻辑,在维护期间临时地处理外部系统故障或意外系统问题
> 断路器是现代软件开发中使用的一种设计模式。 它用于检测故障并封装防止故障不断复发生、维护期间临时外部系统故障或意外系统困难的逻辑
## Programmatic Example
## 程序示例
那么,这一切是如何实现的呢?考虑到上面的例子,我们将在一个简单的例子中模拟这个功能。一个监控服务(译者:下图的 Monitoring Service模拟了网络应用进行本地和远程调用。
So, how does this all come together? With the above example in mind we will imitate the
functionality in a simple example. A monitoring service mimics the web app and makes both local and
remote calls.
该服务架构如下:
那么,这一切是如何结合在一起的呢? 记住上面的例子,我们将在一个简单的例子中模仿这个功能。 监控服务模仿 Web 应用程序并进行本地和远程调用。
![alt text](../../circuit-breaker/etc/ServiceDiagram.png "Service Diagram")
服务架构如下:
终端用户(译者:上图的 End User应用的代码如下
![alt text](../../../circuit-breaker/etc/ServiceDiagram.png "Service Diagram")
在代码方面,最终用户应用程序是:
```java
@Slf4j
@ -61,44 +67,44 @@ public class App {
var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2,
2000 * 1000 * 1000);
//Create an object of monitoring service which makes both local and remote calls
// 创建一个可以进行本地和远程调用的监控服务对象
var monitoringService = new MonitoringService(delayedServiceCircuitBreaker,
quickServiceCircuitBreaker);
//Fetch response from local resource
// 获取本地资源
LOGGER.info(monitoringService.localResourceResponse());
//Fetch response from delayed service 2 times, to meet the failure threshold
// 从延迟服务中获取响应 2 次,以满足失败阈值
LOGGER.info(monitoringService.delayedServiceResponse());
LOGGER.info(monitoringService.delayedServiceResponse());
//Fetch current state of delayed service circuit breaker after crossing failure threshold limit
//which is OPEN now
// 在超过故障阈值限制后获取延迟服务断路器的当前状态
// 现在是打开状态
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Meanwhile, the delayed service is down, fetch response from the healthy quick service
// 同时,延迟服务宕机,从健康快速服务获取响应
LOGGER.info(monitoringService.quickServiceResponse());
LOGGER.info(quickServiceCircuitBreaker.getState());
//Wait for the delayed service to become responsive
// 等待延迟的服务响应
try {
LOGGER.info("Waiting for delayed service to become responsive");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//Check the state of delayed circuit breaker, should be HALF_OPEN
// 检查延时断路器的状态,应该是HALF_OPEN
LOGGER.info(delayedServiceCircuitBreaker.getState());
//Fetch response from delayed service, which should be healthy by now
// 从延迟服务中获取响应,现在应该是健康的
LOGGER.info(monitoringService.delayedServiceResponse());
//As successful response is fetched, it should be CLOSED again.
// 获取成功响应后,它的状态应该是关闭。
LOGGER.info(delayedServiceCircuitBreaker.getState());
}
}
```
监控服务代码(译者:上图的 monitoring service
监控服务类:
```java
public class MonitoringService {
@ -112,7 +118,7 @@ public class MonitoringService {
this.quickService = quickService;
}
//Assumption: Local service won't fail, no need to wrap it in a circuit breaker logic
// 假设:本地服务不会失败,无需将其包装在断路器逻辑中
public String localResourceResponse() {
return "Local Service is working";
}
@ -144,7 +150,7 @@ public class MonitoringService {
}
}
```
可以看出,它直接进行了获取本地资源的调用,但它对远程(昂贵)服务的调用包装在一个断路器对象中,这样可以防止出现如下故障
可以看出,它直接调用获取本地资源,但它对远程(昂贵)服务的调用包装在断路器对象中,防止故障如下
```java
public class DefaultCircuitBreaker implements CircuitBreaker {
@ -171,11 +177,11 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
DefaultCircuitBreaker(RemoteService serviceToCall, long timeout, int failureThreshold,
long retryTimePeriod) {
this.service = serviceToCall;
// We start in a closed state hoping that everything is fine
// 我们从关闭状态开始希望一切都是正常的
this.state = State.CLOSED;
this.failureThreshold = failureThreshold;
// Timeout for the API request.
// Used to break the calls made to remote resource if it exceeds the limit
// API的超时时间.
// 用于在超过限制时中断对远程资源的调用
this.timeout = timeout;
this.retryTimePeriod = retryTimePeriod;
//An absurd amount of time in future which basically indicates the last failure never happened
@ -183,7 +189,7 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
this.failureCount = 0;
}
// Reset everything to defaults
// 重置所有
@Override
public void recordSuccess() {
this.failureCount = 0;
@ -199,18 +205,18 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
this.lastFailureResponse = response;
}
// Evaluate the current state based on failureThreshold, failureCount and lastFailureTime.
// 根据 failureThresholdfailureCount lastFailureTime 评估当前状态。
protected void evaluateState() {
if (failureCount >= failureThreshold) { //Then something is wrong with remote service
if ((System.nanoTime() - lastFailureTime) > retryTimePeriod) {
//We have waited long enough and should try checking if service is up
// 我们已经等得够久了,应该尝试检查服务是否已启动
state = State.HALF_OPEN;
} else {
//Service would still probably be down
// 服务可能仍会出现故障
state = State.OPEN;
}
} else {
//Everything is working fine
// 一切正常
state = State.CLOSED;
}
}
@ -253,16 +259,15 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
public String attemptRequest() throws RemoteServiceException {
evaluateState();
if (state == State.OPEN) {
// return cached response if the circuit is in OPEN state
// 如果电路处于打开状态,则返回缓存的响应
return this.lastFailureResponse;
} else {
// Make the API request if the circuit is not OPEN
// 如果电路未打开,则发出 API 请求
try {
//In a real application, this would be run in a thread and the timeout
//parameter of the circuit breaker would be utilized to know if service
//is working. Here, we simulate that based on server response itself
//在实际应用程序中,这将在线程中运行,并且将利用断路器的超时参数来了解服务
// 是否正在工作。 在这里,我们根据服务器响应本身模拟
var response = service.call();
// Yay!! the API responded fine. Let's reset everything.
// api 响应正常,重置所有。
recordSuccess();
return response;
} catch (RemoteServiceException ex) {
@ -274,39 +279,39 @@ public class DefaultCircuitBreaker implements CircuitBreaker {
}
```
上述模式如何防止失败的呢?让我们通过它实现的这个有限状态机来解。
上述模式如何防止失败? 让我们通过它实现的这个有限状态机来解。
![alt text](../../circuit-breaker/etc/StateDiagram.png "State Diagram")
![alt text](../../../circuit-breaker/etc/StateDiagram.png "State Diagram")
- 我们`timeout`(超时)、 `failureThreshold` (失败阈值)、`retryTimePeriod`(重试时间周期) 参数初始化断路器对象 ,用于确定 API 的适应性。
- 最初,断路器处于 `closed` 关闭状态,没有发生对 API 的远程调用。
- 每次调用成功,我们就把状态重置为开始时的样子
- 如果失败次数超过了一定的阈值(`failureThreshold`),断路器就会进入 `open` 开启状态,它的作用就像一个开启的电路,阻止远程服务调用,从而节省资源。
- 一旦我们超过重试时间周期(`retryTimePeriod`),断路器就会转到 `half-open` 半启用状态并再次调用远程服务检查服务是否正常,以便我们可以提供最新的响应内容。如果远程服务调用失败会使断路器回到 `open` 状态,并在重试超时后进行另一次尝试;如果远程服务调用成功则使断路器进入 `closed` 状态,这样一切又开始正常工作。
- 我们使用某些参数初始化断路器对象:`timeout``failureThreshold` `retryTimePeriod`,这有助于确定 API 的性。
- 最初,我们处于“关闭状态,没有发生对 API 的远程调用。
- 每次调用成功,我们都会将状态重置为开始时的状态
- 如果失败次数超过某个阈值我们将进入“open”状态这就像开路一样,阻止远程服务调用,从而节省资源。 (这里,我们从 API 返回名为 ```stale response``` 的响应)
- 一旦超过重试超时时间,我们就会进入“半开”状态并再次调用远程服务检查服务是否正常工作,以便我们可以提供新鲜内容。 失败将其设置回“打开”状态,并在重试超时时间后进行另一次尝试,而成功将其设置为“关闭”状态,以便一切重新开始正常工作。
## 类图
![alt text](../../circuit-breaker/etc/circuit-breaker.urm.png "Circuit Breaker class diagram")
![alt text](../../../circuit-breaker/etc/circuit-breaker.urm.png "Circuit Breaker class diagram")
## 适用场景
## 适用
在以下场景下,可以使用断路器模式
在以下情况下使用断路器模式
- 构建一个高可用的应用程序,某些服务的失败不会导致整个应用程序的崩溃
- 构建一个持续运行(长期在线)的应用程序,以便其组件可以在不完全关闭的情况下进行升级。
- 构建一个容错应用程序,其中某些服务的故障不应导致整个应用程序宕机
- 构建一个持续运行(永远在线)的应用程序,这样它的组件可以在不完全关闭的情况下升级。
## 相关模式
- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry)
## 现实案例
## 真实世界例子
* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker)
* [Netflix Hystrix API](https://github.com/Netflix/Hystrix)
## 引用
## 鸣谢
* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42)
* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html)
* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a)
* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)