itsoneiota / circuit-breaker
One iota 断路器
Requires
- php: >=5.5
- itsoneiota/cache: ^1.0
- itsoneiota/count: 2.0.2
- psr/log: ^1.0
Requires (Dev)
This package is not auto-updated.
Last update: 2024-09-28 18:35:37 UTC
README
概述
断路器可以用来保护系统免受外部依赖失败的影响。它可以跟踪在一定时间内的服务调用成功和失败情况,如果前一个时间段的失败率超过了设定的阈值,则会“跳闸”。
如果电路应该继续发送请求,则称其为“关闭”状态,如果不再发送请求,则称为“打开”状态。如果未达到给定的最小请求次数,则电路将保持关闭状态。一个附加的功能允许以等于前一个时间段成功率的概率向服务发送请求。
安装
composer require itsoneiota/circuit-breaker
测试
./vendor/bin/phpunit
基本用法
构建器
构建断路器最简单的方式是使用构建器类。
$this->breaker = CircuitBreakerBuilder::create('myService')->withCache($cache)->build();
其中 myService 是你依赖的服务名称,而 $cache 是一个 \itsoneiota\cache\Cache 实例。所有使用相同缓存和服务名称的断路器将共享它们的统计信息,并将一起打开和关闭。
隔离远程服务调用
假设我们正在调用远程服务,并希望保护自己不受它糟糕表现的影响。
public function getRemoteStuff(){
// If the circuit is open, don't make the request.
if(!$this->breaker->isClosed()){
$this->breaker->registerRejection();
// Handle how you want to respond if the circuit is open here.
// Maybe throw an exception, or return a cached value.
return NULL;
}
// Now make the request...
$response = file_get_contents('http://www.example.com/api/stuff');
if($response === FALSE){
// Register the failure and return a default value.
$this->breaker->registerFailure();
return NULL;
}
// Success!
$this->breaker->registerSuccess();
return $response;
}
配置
断路器可以通过直接方式或通过构建器进行配置。构建器通常会使这个过程更加友好且易于阅读,因此这里将记录下来。以下方法可以以流畅的方式链接在一起,例如:
CircuitBreakerBuilder::create('foo')
->withLogger($logger)
->withMemcachedServer($host, $port)
->withTimeProvider($tp)
->withMinimumRequestsBeforeTrigger(100)
->withPercentageFailureThreshold(60)
->withProbabilisticDynamics()
->withRecoveryFactor(2.5)
->enabled()
->build();
enabled() / disabled() (默认:启用)
分别打开或关闭电路断路器。启用时,断路器会在响应过多失败的请求时“跳闸”。禁用时,它将继续记录成功/失败/拒绝统计信息,但不会“跳闸”。
withSamplePeriod($period) (默认 60)
在做出决定之前,聚合成功和失败的时间段,以秒为单位。
withMinimumRequestsBeforeTrigger($min) (默认 3)
在电路做出决定之前必须发出的最小请求次数。
withPercentageFailureThreshold($threshold) (默认 50)
将触发电路“跳闸”的失败率百分比。
withProbabilisticDynamics() / withDeterministicDynamics() (默认:确定性的)
断路器跳闸时的动态。如果为确定性,则电路将完全打开,在整个时间段内不允许任何流量通过。如果为概率性的,则电路将允许一定比例的请求通过,并在随后的时间段内逐渐增加请求的数量。
withRecoveryFactor($factor) (默认 2)
随后的时间段中限制放松的速度。请参阅下面的“恢复动态”。
withCache() / withCacheBuilder() / withMemcachedServer($host, $port)
这些方法帮助向断路器提供Cache实例。由于CircuitBreaker旨在将您的系统与其外部依赖解耦,因此,它的缓存依赖性不引起故障是很重要的。如果您的应用已经有一个工作的Cache实例,那么将其提供给withCache()将正常工作。如果缓存实例尚未构建,则最好向withCacheBuilder()提供一个回调函数,或将您的memcached服务器的主机和端口传递给withMemcachedServer()。这允许构建器隔离构建缓存实例的任何困难,并在有问题时提供默认值。默认值将几乎毫无用处,但有助于避免崩溃。以下是一个示例:
$cacheBuilder = function(){
// Do risky cache building here…
return $cache;
};
CircuitBreakerBuilder::create('foo')->withCacheBuilder($cacheBuilder)->build();
withLogger($logger)
设置一个Psr\Log\LoggerInterface实例,该实例可以用于在构建时间记录任何错误。构建错误使用critical级别记录。通常,这将是连接到memcached的问题。如果没有记录错误,断路器将静默失败,您可能永远不知道。
开启或关闭?
电路默认是关闭的。
随着断路器通知成功和失败的请求,它会在给定样本周期内收集有关电路的统计数据。默认情况下,样本周期为60秒,但可以设置为任何您喜欢的值。断路器使用上一个样本周期的统计数据来决定是否保持开启或关闭。
如果已达到最小请求阈值,并且上一个周期内的失败率百分比超过了失败率阈值,则断路器将“跳闸”,并且isClosed()将返回FALSE。
可能关闭?
如果一个依赖项可能会完全崩溃,那么二进制开启/关闭状态将非常适合。如果一个依赖项有时在负载下变得不可靠,但没有完全失败,我们可以降低对该依赖项的请求,直到它恢复。为了帮助这些情况,我们可以根据上一个样本周期的成功率以概率使电路开启。
要设置概率性,在构建器上设置withProbabilisticDynamics()方法,或在断路器本身上调用setProbabilisticDynamics(TRUE)。现在,在所有常规情况下,isClosed()将返回TRUE。如果满足跳闸条件,现在isClosed()将以上一个周期成功率相等的概率返回TRUE。例如,假设在一个周期内我们对一个依赖项进行了100次请求,但只有20次成功。在概率性动力学中,isClosed()大约有20%的时间会返回TRUE。
恢复动力学
为了使电路不会立即“闭合”,动力学将逐步从一期到下一期增加节流。恢复速度可以使用recoveryFactor属性设置。例如,在一个80%失败率的周期后,只有20%的请求会被允许通过。如果所有通过电路的请求都成功了,下一期将有20% * recoveryFactor的请求被允许通过。恢复被限制在上一个周期的成功率与节流 * recoveryFactor中的较小值。
时间提供者
断路器根据当前时间在缓存桶中记录统计数据。时间是TimeProvider实例提供的。这里有几个选项:
SystemTimeProvider是time()的一个简单包装。FixedTimeProvider将始终给出相同的时间。可能更快,谁知道呢?也很有用进行测试。- 自己实现:如果您有特殊要求,可以自己实现
TimeProvider。
随机数生成器
断路器在部分关闭时使用随机数,具有概率动力学。对于断路器的随机数生成不需要太复杂,但它有助于将 rand() 数生成替换为确定性方法。为了帮助实现这一点,将 RandomNumberGenerator 实例注入到构造函数中。在正常使用中不应需要对此进行调整。