odesk / phystrix
协议无关的延迟和故障隔离库
Requires
- php: >=5.3.3
- zendframework/zend-config: ~2.2
- zendframework/zend-di: ~2.2
Requires (Dev)
- phpunit/phpunit: ~4.2
README
关于Phystrix
在具有PHP前端的前端分布式系统中,应用程序会与多个远程服务进行通信。无论是您自己的服务集合、第三方RESTful API还是需要网络交互的遗留组件:在复杂、高负载系统中,偶尔的故障是无法避免的。
Phystrix通过跟踪各种指标并防止重复失败来保护对远程资源的访问点。
如果某个服务失败次数过多,为了避免情况恶化,Phystrix将暂时停止向其发出请求。当服务恢复时,Phystrix允许客户端应用程序再次访问它。
理解Phystrix
Phystrix不仅受到了Netflix公司为Java开发的令人惊叹的Hystrix库的极大启发,还试图遵循该库的最佳实践。您会注意到配置参数也是相同的,以及其内部工作的很多方面。
尽管目前Phystrix的文档资料并不多,但您也可以使用Hystrix维基作为额外的信息来源,以了解某些功能是如何工作的等。
安装
安装Phystrix的推荐方式是使用Composer
"require": { "odesk/phystrix": "dev-master" }
为了在请求之间存储和共享指标,Phystrix使用APC,因此请确保已启用PHP扩展。
Php 7.2
在PHP 7中,apcu
的API发生了变化。除了安装apcu
外,您还需要安装apcu-bc才能使用Phystrix。必须将向后兼容层扩展加载在apcu
之后。
使用
为了保护对远程服务的访问点,我们使用命令模式。以下是一个最小实现示例:
use Odesk\Phystrix\AbstractCommand; /** * All commands must extends Phystrix's AbstractCommand */ class MyCommand extends AbstractCommand { protected $name; public function __construct($name) { $this->name = $name; } /** * This function is called internally by Phystrix, only if the request is allowed * * @return mixed */ protected function run() { return 'Hello ' . $this->name; } }
如果您需要将具有Phystrix特定依赖项的命令预先配置,则需要从与您的对象共享的特殊工厂中获取它。例如,在您的控制器中,您会这样做:
$myCommand = $phystrix->getCommand('MyCommand', 'Alex'); // 'Alex' is passed to MyCommand's constructor $result = $myCommand->execute();
注意,您传递给工厂getCommand方法的额外参数会被转发到命令的构造函数。
工厂的实例化方法如下所示
use Zend\Config\Config; use Odesk\Phystrix\ApcStateStorage; use Odesk\Phystrix\CircuitBreakerFactory; use Odesk\Phystrix\CommandMetricsFactory; use Odesk\Phystrix\CommandFactory; $config = new Config(require 'phystrix-config.php'); $stateStorage = new ApcStateStorage(); $circuitBreakerFactory = new CircuitBreakerFactory($stateStorage); $commandMetricsFactory = new CommandMetricsFactory($stateStorage); $phystrix = new CommandFactory( $config, new \Zend\Di\ServiceLocator(), $circuitBreakerFactory, $commandMetricsFactory, new \Odesk\Phystrix\RequestCache(), new \Odesk\Phystrix\RequestLog() );
您如何存储配置文件取决于您自己。Phystrix依赖于Zend\Config来管理配置。在这种情况下,phystrix-config.php是一个PHP数组。
return array( 'default' => array( // Default command configuration 'fallback' => array( // Whether fallback logic of the phystrix command is enabled 'enabled' => true, ), 'circuitBreaker' => array( // Whether circuit breaker is enabled, if not Phystrix will always allow a request 'enabled' => true, // How many failed request it might be before we open the circuit (disallow consecutive requests) 'errorThresholdPercentage' => 50, // If true, the circuit breaker will always be open regardless the metrics 'forceOpen' => false, // If true, the circuit breaker will always be closed, allowing all requests, regardless the metrics 'forceClosed' => false, // How many requests we need minimally before we can start making decisions about service stability 'requestVolumeThreshold' => 10, // For how long to wait before attempting to access a failing service 'sleepWindowInMilliseconds' => 5000, ), 'metrics' => array( // This is for caching metrics so they are not recalculated more often than needed 'healthSnapshotIntervalInMilliseconds' => 1000, // The period of time within which we the stats are collected 'rollingStatisticalWindowInMilliseconds' => 1000, // The more buckets the more precise and actual the stats and slower the calculation. 'rollingStatisticalWindowBuckets' => 10, ), 'requestCache' => array( // Request cache, if enabled and a command has getCacheKey implemented // caches results within current http request 'enabled' => true, ), 'requestLog' => array( // Request log collects all commands executed within current http request 'enabled' => false, ), ), 'MyCommand' => array( // Command specific configuration 'fallback' => array( 'enabled' => false ) ) );
在实例化时,将特定于命令的配置与默认配置合并。"MyCommand"在这种情况下是命令键。默认情况下,它与命令的类名相同,但您可以通过重写受保护的getCommandKey方法来设置它。
/** * This function defines the command key to use for this command * * @return string */ protected function getCommandKey() { return 'CustomCommandKey'; }
Phystrix只与命令键一起工作。如果您有两个具有相同命令键的不同命令 - Phystrix将像对待单个实体一样收集指标、禁用和启用请求。这可以用于对命令进行分组。
有时,您可能需要在特定上下文中使用命令时更改一个参数
use Zend\Config\Config; $myCommand = $phystrix->getCommand('MyCommand', 'Alex'); $myCommand->setConfig(new Config(array('requestCache' => array('enabled' => false)))); $result = $myCommand->execute();
注意,您设置的配置与之前设置的值合并。
特性
后备
对于命令,您可以指定后备逻辑,该逻辑在失败或远程服务被阻塞时执行
class GetAvatarUrlCommand extends AbstractCommand { protected $user; public function __construct($user) { $this->user = $user; } protected function run() { $remoteAvatarService = $this->serviceLocator->get('avatarService'); return $remoteAvatarService->getUrlByUser($this->user); } /** * When __run__ fails for some reason, or when Phystrix doesn't allow the request in the first place, * this function result will be returned instead * * @return string */ protected function getFallback() { // we failed getting user's picture, so showing a generic no-photo placeholder instead. return 'http://example/avatars/no-photo.jpg'; } }
如果您想使用需要网络逻辑的回退方案,请确保将其“包装”成它自己的Phystrix命令。
请求缓存
当启用请求缓存时,它会在单个HTTP请求内缓存命令执行结果,这样您就无需担心过度加载网络上的数据。
结果按照命令键和缓存键进行缓存。要定义缓存键生成逻辑,请实现受保护的getCacheKey方法
protected function getCacheKey() { return 'cache_' . $this->user; }
超时
Hystrix for Java 允许您设置命令允许运行的具体时间。它所做的就是限制命令运行时的线程时间。然而,在PHP中我们无法这样做,因为我们只有当前线程的上下文。
建议的方法是手动在用于访问远程服务的库中配置超时。
假设您为MyCommand配置了以下Phystrix配置
'MyCommand' => array( 'fallback' => array( 'enabled' => false ), 'timeout' => 2000, // milliseconds )
其中,“timeout”是一个自定义参数,Phystrix不会使用它。您可以在Phystrix配置中指定任何任意参数,并且它们将在命令中可用
protected function run() { $remoteAvatarService = $this->serviceLocator->get('avatarService'); return $remoteAvatarService->getUrlByUser($this->user); } /** * Custom preparation logic, preceding command execution */ protected function prepare() { $remoteAvatarService = $this->serviceLocator->get('avatarService'); if ($this->config->__isset('timeout')) { // if the timeout is exceeded an exception will be thrown $remoteAvatarService->setTimeout($this->config->get('timeout')); } }
客户端可能是您下载的第三方库,或者来自Zend Framework、Symfony等框架的HTTP客户端实例,或者您自己编写的代码。
当然,必须在每个命令中添加这一点并不理想。通常,您将有一组抽象命令,针对您的特定用例。例如,您可能有 GenericCurlCommand 或 GenericGoogleApiCommand,而 MyCommand 将扩展其中的一个。
自定义依赖项
由于您从特殊工厂获取命令,您需要一种方法将自定义依赖项注入到您的命令中,例如HTTP客户端实例。
一种方法是通过扩展 Odesk\Phystrix\CommandFactory,创建自己的工厂,并注入所需的内容。
或者,配置在构造函数中接受的 Odesk\Phystrix\CommandFactory 的定位器实例。
服务定位器可以是任何实现非常基础的 Zend\Di\LocatorInterface 的东西。您可以注入一个IoC容器,它将懒加载实例,或者您可以使用更简单、预先配置的 Zend\Di\ServiceLocator 实例。
$serviceLocator = \Zend\Di\ServiceLocator(); $googleApiRemoteService = new GoogleApi(...); $serviceLocator->set('googleApi', $googleApiRemoteService); $phystrix = new CommandFactory( $config, $serviceLocator, $circuitBreakerFactory, $commandMetricsFactory, new \Odesk\Phystrix\RequestCache() );
您可以通过以下方式在命令中访问服务定位器
protected function run() { $googleApi = $this->serviceLocator->get('googleApi'); return $googleApi->fetchAllEmail(); }
请求日志
一个用于性能监控的有用功能。当启用时,允许您检索当前HTTP请求期间执行的命令列表
/** @var RequestLog $requestLog */ $commands = $requestLog->getExecutedCommands();
您得到的是一个实际命令实例的数组。对于每个命令,您可以获取其执行时间(以毫秒为单位)
$command->getExecutionTimeInMilliseconds();
以及事件列表,例如 "SUCCESS","FAILURE","TIMEOUT","SHORT_CIRCUITED","FALLBACK_SUCCESS","FALLBACK_FAILURE","EXCEPTION_THROWN","RESPONSE_FROM_CACHE"
$command->getExecutionEvents();
Hystrix Turbine和Dashboard支持
待定
许可证
版权所有 2013-2017 Upwork Global Inc. 保留所有权利。
Phystrix遵循Apache License,版本2.0(“许可证”);除非按照适用的法律要求或书面同意,否则不得使用此文件,除非遵守许可证。您可以在以下位置获得许可证副本:
https://apache.ac.cn/licenses/LICENSE-2.0
除非适用法律要求或书面同意,否则在许可证下分发的软件按“原样”分发,不提供任何明示或暗示的保证或条件。有关许可证的具体语言管辖权限和限制,请参阅许可证。