geggleto/php-circuit-breaker

PHP 电路断路器组件

0.3.1 2016-02-22 15:29 UTC

This package is auto-updated.

Last update: 2024-08-29 03:31:33 UTC


README

Build Status

什么是php-circuit-breaker

这是一个组件,帮助您优雅地处理外部服务的故障和超时(通常是远程、第三方服务)。

这是一个提供非常易于使用的电路断路器组件的库。它不需要外部依赖,并提供了APC和Memcached的默认存储实现,但可以通过多种方式扩展。

框架支持

这个库不需要任何特定的PHP框架,您只需要PHP 5.6或更高版本。

动机与好处

  • 允许应用程序在无需人工干预的情况下检测故障并适应其行为。
  • 通过在模块中添加故障安全功能来提高服务的健壮性。

安装

"require": {
    "geggleto/php-circuit-breaker": "^0.3"
},

之后,您应该更新composer依赖项,然后就可以开始使用了。

用例 - 非关键功能

  • 您的应用程序有一个非关键功能,如:用户跟踪、统计、推荐等
  • 此可选功能使用远程服务,这会导致您的应用程序出现故障。
  • 当“非关键功能”失败时,您希望保持应用程序和核心流程可用。

您的应用程序代码可能如下所示

    $factory = new Ejsmont\CircuitBreaker\Factory();
    $circuitBreaker = $factory->getSingleApcInstance(30, 300);

    $userProfile = null;
    if( $circuitBreaker->isAvailable("UserProfileService") ){
        try{
            $userProfile = $userProfileService->loadProfileOrWhatever();
            $circuitBreaker->reportSuccess("UserProfileService");
        }catch( UserProfileServiceConnectionException $e ){
            // network failed - report it as failure
            $circuitBreaker->reportFailure("UserProfileService");
        }catch( Exception $e ){
            // something went wrong but it is not service's fault, dont report as failure
        }
    }
    if( $userProfile === null ){
        // for example, show 'System maintenance, you cant login now.' message
        // but still let people buy as logged out customers.
    }

用例 - 支付网关

  • Web应用程序依赖于第三方服务(例如支付网关)。
  • Web应用程序需要跟踪第三方服务是否不可用。
  • 应用程序不能变慢/不可用,它必须告诉用户功能有限或隐藏它们。
  • 应用程序在使用结账页面渲染之前使用电路断路器,如果特定的支付网关不可用,则将从用户那里隐藏支付选项。

如您所见,这是一个非常强大的概念,可以在运行时选择性禁用功能,但仍然允许核心业务流程不间断。

与支付服务通信的后端可能如下所示

    $factory = new Ejsmont\CircuitBreaker\Factory();
    $circuitBreaker = $factory->getSingleApcInstance(30, 300);

    try{
        // try to process the payment
        // then tell circuit breaker that it went well
        $circuitBreaker->reportSuccess("PaymentOptionOne");
    }catch( SomePaymentConnectionException $e ){
        // If you get network error report it as failure
        $circuitBreaker->reportFailure("PaymentOptionOne");
    }catch( Exception $e ){
        // in case of your own error handle it however it makes sense but
        // dont tell circuit breaker it was 3rd party service failure
    }

由于您正在记录失败和成功的操作,您现在可以在前端以及隐藏失败的支付选项。

渲染可用支付选项的前端可能如下所示

    $factory = new Ejsmont\CircuitBreaker\Factory();
    $circuitBreaker = $factory->getSingleApcInstance(30, 300);

    if ($circuitBreaker->isAvailable("PaymentOptionOne")) {
        // display the option
    }

功能

  • 通过单个电路断路器实例跟踪多个服务。
  • 提供可插拔的后端适配器,默认提供APC和Memcached。
  • 可自定义的服务阈值。您可以定义需要多少次失败才认为服务已关闭。
  • 可自定义的重试超时。您不希望永久禁用服务。在提供的时间超时后,电路断路器将允许单个进程尝试
  • 此分支包括在服务修改为失败状态时执行代码块的能力

触发断路器

当提供每个服务的TrippedHandler时,可以在断路器触发时执行代码。TrippedHandler负责记录您的服务故障。断路器将响应两种状态:不可用和重试。第一次断路器触发时,将发送不可用消息“服务不再可用”,而在每次重试尝试之后,将发送“正在重试服务”消息。为这些消息提供了Get/Set方法。

以下是一个EmailHandler的示例

use Ejsmont\CircuitBreaker\TrippedHandlerInterface;

class EmailHandler implements TrippedHandlerInterface
{
    protected $targetEmail = '';
    
    protected $headers = '';
    
    public function __construct($targetEmail)
    {
        $this->targetEmail = $targetEmail;
        $this->headers = 'From: xxx@xxx.ca' . "\r\n" .
            'Reply-To: xxx@xxx.ca' . "\r\n" .
            'X-Mailer: PHP/' . phpversion();
    }

    public function __invoke($serviceName, $count, $message)
    {
        mail($this->targetEmail, "Service Outage: " . $serviceName, $message, $this->headers);
    }
}

以下是如何注册它。这为“数据库”服务添加了一个处理程序

$circuitBreaker = $factory->getSingleApcInstance(5, 30);
$circuitBreaker->registerHandler("Database", new \Handler\EmailHandler("your_email@your_domain.com"));

性能影响

电路断路器的开销可以忽略不计。

APC实现大约需要0.0002秒来执行isAvailable()操作,然后报告Success()或reportFailure()。

Memcache适配器在与本地memcached进程通信时在大约0.0005秒范围内。

唯一可能影响性能的因素是网络连接时间。如果您选择使用远程memcached服务器或实现自己的自定义StorageAdapter。

详细信息

在文档更新之前,您可以在我的博客上了解更多关于熔断器及其实现的概念:http://artur.ejsmont.org/blog/circuit-breaker

一些实现细节已更改,但核心逻辑保持不变。

(更新) 您可以阅读我的博客,了解我是如何使用这个包的,http://bolt.tamingtheelephpant.com/page/circuit-breakers-failing-gracefully

单元测试

phpunit -c tests/phpunit.xml --bootstrap tests/bootstrap.php tests

作者