PHystrix 参照了 Netflix的项目 Hystrix。我们叫豪猪。豪猪的作用。
部署hystrix-dashboard界面工具。
作为一个压根不懂java的程序员。跑java程序当然不是难事。
打war包
wiki中有教你的。../gradlew jettyRun
。但也许实际上会遇到一些问题。比如,我用gradlew 会提示我下载安装对应的gradle。结果没下载下来。尴尬啊。在了解了什么是gradlew(会指定对应的版本)之后。我用brew intall gradle 下载了比较新的版本。然后直接用gradle jettyRun运行。默认是跑得 是 7979端口。不用打包就可以跑。
war包
gradle build 执行。war包在 /hystrix-dashboard/build/libs 下
部署到tomcat下
下载一个tomcat。bin目录下点击运行文件直接运行(linux有start_up.sh)。这玩意儿比nginx简单。一个war包扔到 webapps目录下就执行了。
浏览器输入:http://localhost:8080/hystrix-dashboard
PHystrix的准备
需要准备好 apc模块。php7及以上安装 apcu。
pecl 的方式安装。
可以通过运行 apc.php文件,看apc使用情况。
具体的操作配置,看下面的参考。这里注意你的php版本。
参考链接: 《PHP之APC缓存详细介绍》http://www.cnblogs.com/Alight/archive/2013/06/06/3121000.html
phystrix-dashboard 代码,为java的dashboard工具提供数据流
文档中的代码即可
$config = new Zend\Config\Config(array(/* ... */));
$metricsPoller = new \Odesk\PhystrixDashboard\MetricsEventStream\ApcMetricsPoller($config);
$metricsServer = new \Odesk\PhystrixDashboard\MetricsEventStream\MetricsServer($metricsPoller);
$metricsServer->run();
我们创建一个控制器 叫做 DashBoard,写个方法叫Log。我们请求这个方法。
惊喜的发现 数据流出来了。 ok,我们打开dashBoard的界面。然后,开心的填入链接。添加监听观察。然后开始不开心了。
参考链接: https://github.com/upwork/phystrix-dashboard
PHP豪猪集成遇到的问题。
不开心的地方在于。dashboard 展示出现死循环。满屏的 PhystrixCommand\UnReadCntCommand
。愣是没出现图形的东东。看下图。
于是,开始郁闷。为什么会出现死循环。我对比了别人写的demo。跑了下,没有死循环,显示正常。我摘了端数据流。compare了下,感觉没什么差异。那就奇怪了。既然数据格式一样。问题只能在js端排查。
于是开始找循环的前端代码。
在hystrixCommand.js
文件中搜self.eventSourceMessageListener
,在这个方法中。获取数据并解析。我对比了正常的data跟我的data。格式一样。那么问题。还不是出现数据结构上。
那么开始找展示的html(通过id搜索下)。中间展示图形html代码在hystrixCircuitContainer.html
中。
<div class="monitor" id="CIRCUIT_<%= name + '_' + index %>" style="position:relative;">
发现界面死循环,会产生多个相同的id值。那么我怀疑id是不起作用的,所以数据无法填充。导致图形界面出不来。进一步验证。$("#CIRCUIT_PhystrixCommand\UnReadCntCommand_0").length。打印出来是0 ,逆天了。
那么在js文件中,肯定有相关的操作。比如定位id填充数据的操作。于是,在hystrixCommand.js
代码中找到如下这个函数displayCircuit
。这个函数中有对长度进行判断,然后进行相关的数据渲染操作。
if(!$('#CIRCUIT_' + data.escapedName).length) {
// args for display
if(self.args.includeDetailIcon != undefined && self.args.includeDetailIcon) {
data.includeDetailIcon = true;
}else {
data.includeDetailIcon = false;
}
// it doesn't exist so add it
var html = tmpl(hystrixTemplateCircuitContainer, data);
console.log('#CIRCUIT_' + data.escapedName);
console.log("3333333333330000");
// remove the loading thing first
$('#' + containerId + ' span.loading').remove();
// now create the new data and add it
$('#' + containerId + '').append(html);
// add the default sparkline graph
d3.selectAll('#graph_CIRCUIT_' + data.escapedName + ' svg').append("svg:path");
// remember this is new so we can trigger a sort after setting data
addNew = true;
}
既然发现问题。如何解决。key中带\
所以id元素length为0。那么就在数据渲染之前,把escapedName中的\
替换成空字符串。
找到了这个方法preProcessData
(UI展示钱的数据处理),找到了如下代码。
data.escapedName = data.name.replace(/([ !"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g,'\\$1') + '_' + data.index;
于是在这行代码上面加了一行 data.name = data.name.replace("\\", '');
。问题就这么解决了。
但,这样结束真的好吗?
我们为什么不在写缓存的时候,用不带\
的Key呢?
在文件AbstractCommand
中,有一个属性 protected $commandKey
。在我们的文件继承中。我们设置这个属性即可。我们在类PhystrixCommand\UnReadCntCommand
中。继承这个属性把key设置成UnReadCntCommand
即可。
看来都是命名空间惹的祸。为什么存的key是命名空间的呢?那一定是调用的时候,内部存到了APC里面。在文件AbstractCommand
有这个代码。代码很容易明白,你不指定commandKey。那么通过class名字当做key。于是,才有了命名空间的key。
public function getCommandKey()
{
if ($this->commandKey) {
return $this->commandKey;
} else {
// If the command key hasn't been defined in the class we use the current class name
return get_class($this);
}
}
参考资料: