<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://www.jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://www.jackxiang.com/post/10747/</link>
<title><![CDATA[[实践OK]协程 shell_exec 如何捕获标准错误流]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Tue, 03 Nov 2020 06:30:48 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10747/</guid> 
<description>
<![CDATA[ 
	问题：用Co&#92;System::exec()执行了一个不存在的命令时，错误信息会直接打印到屏幕，而不是返回错误信息。<br/>怎么办：实际上Swoole提供的System::exec()行为上与PHP的shell_exec是完全一致的，我们写一个shell_exec的同步阻塞版本，执行后发现同样拿不到标准错误流输出的内容，会被直接打印到屏幕。<br/>答案：&nbsp;&nbsp;使用proc_open+hook实现。<br/>现象：<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
$result = shell_exec(&#039;unknown&#039;);
var_dump($result);
</textarea><br/><br/>==================================================================<br/>#php tt.php<br/>PHP Warning:&nbsp;&nbsp;shell_exec() has been disabled for security reasons in /data/www/testswoole/tt.php on line 2<br/>NULL<br/><br/>估计整成错误输出了，于是用：<br/>php tt.php &gt;/dev/null 2&gt;&amp;1<br/><br/>果然，怎么办？加入管道，将此错误指向新的文件描述符。<br/><br/><br/><br/>前置：打开php.ini里面的proc_open禁用函数。<br/>#cat t.php <br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
Swoole&#92;Runtime::setHookFlags(SWOOLE_HOOK_ALL);
Swoole&#92;Coroutine&#92;run(function () &#123;
&nbsp;&nbsp;&nbsp;&nbsp;$descriptorspec = array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 =&gt; array(&quot;pipe&quot;, &quot;r&quot;),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1 =&gt; array(&quot;pipe&quot;, &quot;w&quot;),
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2 =&gt; array(&quot;pipe&quot;, &quot;w&quot;),
&nbsp;&nbsp;&nbsp;&nbsp;);

&nbsp;&nbsp;&nbsp;&nbsp;$process = proc_open(&#039;unknown&#039;, $descriptorspec, $pipes);
&nbsp;&nbsp;&nbsp;&nbsp;var_dump($pipes);

&nbsp;&nbsp;&nbsp;&nbsp;var_dump(fread($pipes[2], 8192));
&nbsp;&nbsp;&nbsp;&nbsp;$return_value = proc_close($process);

&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;command returned $return_value&#92;n&quot;;
&#125;);

</textarea><br/><br/>#php t.php <br/>array(3) &#123;<br/>&nbsp;&nbsp;[0]=&gt;<br/>&nbsp;&nbsp;resource(4) of type (stream)<br/>&nbsp;&nbsp;[1]=&gt;<br/>&nbsp;&nbsp;resource(5) of type (stream)<br/>&nbsp;&nbsp;[2]=&gt;<br/>&nbsp;&nbsp;resource(6) of type (stream)<br/>&#125;<br/>string(31) &quot;sh: unknown: command not found<br/>&quot;<br/>command returned 32512<br/><br/>代码来自rango：https://mp.weixin.qq.com/s/z7SPy-tV3hsQqLXZ-tKlZw
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10348/</link>
<title><![CDATA[[实践OK]swoole进程间通讯之将管道导出为一个SwooleCoroutineSocket对象，通过读写此Socket就可以实现通信。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Wed, 13 Nov 2019 08:10:14 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10348/</guid> 
<description>
<![CDATA[ 
	（以下实例用到了assert，请确保php7的zend.assertions=1，或者 php -d &quot;zend.assertions=1&quot; 临时启用进行测试）<br/><br/>cat&nbsp;&nbsp;process.croutine.php <br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
$proc1 = new &#92;swoole_process(function (swoole_process $proc) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;$socket = $proc-&gt;exportSocket();
&nbsp;&nbsp;&nbsp;&nbsp;echo $socket-&gt;recv();
&nbsp;&nbsp;&nbsp;&nbsp;$socket-&gt;send(&quot;hello proc2&#92;n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;proc1 stop&#92;n&quot;;
&#125;, false, 1, true);

assert($proc1-&gt;start());

$proc2 = new &#92;swoole_process(function (swoole_process $proc) use ($proc1) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;Co::sleep(0.01);
&nbsp;&nbsp;&nbsp;&nbsp;$socket = $proc1-&gt;exportSocket();
&nbsp;&nbsp;&nbsp;&nbsp;$socket-&gt;send(&quot;hello proc1&#92;n&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;echo $socket-&gt;recv();
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;proc2 stop&#92;n&quot;;
&#125;, false, 0, true);

assert($proc2-&gt;start());

swoole_process::wait(true);
swoole_process::wait(true);
</textarea><br/><br/>php -d &quot;zend.assertions=1&quot;&nbsp;&nbsp;process.croutine.php <br/>hello proc1<br/>proc1 stop<br/>hello proc2<br/>proc2 stop<br/><br/>来自：https://wiki.swoole.com/wiki/page/1061.html
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10292/</link>
<title><![CDATA[[实践OK]关于swoole里面的通讯四次挥手问题。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Tue, 17 Sep 2019 03:18:34 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10292/</guid> 
<description>
<![CDATA[ 
	server.php <br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
$server = new swoole_server(&quot;127.0.0.1&quot;, 6666,SWOOLE_PROCESS);&nbsp;&nbsp;#Process 时千万不要抛出错误，容易出现CLOSE_WAIT,专门有一个主进程的线程在处理连接，不会存在backlog塞满。
#$server = new swoole_server(&quot;127.0.0.1&quot;, 6666,SWOOLE_BASE);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#都是Worker进程去accept，会发Fin包，服务器端不会进入CLOSE_WAIT，但是backlog容易塞满,connfd = accept( listenfd, (struct sockaddr *)&amp;clientaddr, &amp;clilen );
$server-&gt;on(&#039;connect&#039;, function ($server, $fd)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;connection open: &#123;$fd&#125;&#92;n&quot;;
&#125;);
$server-&gt;on(&#039;receive&#039;, function ($server, $fd, $reactor_id, $data) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;$server-&gt;send($fd, &quot;Swoole: &#123;$data&#125;&quot;);
&nbsp;&nbsp;&nbsp;&nbsp;$server-&gt;close($fd);
&#125;);
$server-&gt;on(&#039;close&#039;, function ($server, $fd) &#123;#Sleep在里面后，Sleep函数的出现无法调底层的Close方法，导致出现服务端一直处于CLOSE_WAIT，出现连接状态，客户端在FIN_WAIT2状态。
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;connection close: &#123;$fd&#125;&#92;n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;#die(); # 进程通出
&nbsp;&nbsp;&nbsp;&nbsp;sleep(1000);
&#125;);
$server-&gt;start();
</textarea><br/><br/>ACCEPT队列（全连接队列）：由listen()函数的第二个参数 backlog 指定，内核硬限制由 net.core.somaxconn 限制，即实际的值由min(backlog,somaxconn) 来决定。表示已完成连接的队列，等待被 accept系统调用取走。<br/><br/>php server.php <br/>connection open: 1<br/>[2019-09-17 06:47:18 *9116.0]&nbsp;&nbsp; NOTICE&nbsp;&nbsp;swFactoryProcess_finish (ERRNO 1004): send 25 byte failed, because connection[fd=1] is closed<br/>connection close: 1<br/><br/>client.php<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
var_dump($client-&gt;connect(&#039;127.0.0.1&#039;,6666));
$client-&gt;send(&quot;date to kill conn&quot;);
$client-&gt;close();
sleep(1000);
</textarea><br/><br/>netstat -lantp&#124;grep 6666&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>tcp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 127.0.0.1:48344&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 127.0.0.1:6666&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FIN_WAIT2&nbsp;&nbsp; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#客户端进入&nbsp;&nbsp;FIN_WAIT2 状态&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>tcp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0 127.0.0.1:6666&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;127.0.0.1:48344&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CLOSE_WAIT&nbsp;&nbsp;9110/php&nbsp;&nbsp;&nbsp;&nbsp; #服务器端进入CLOSE_WAIT<br/><br/><br/>https://blog.csdn.net/Tanswer_/article/details/78375317<br/><br/><br/>SYN队列（半连接队列）：由/proc/sys/net/ipv4/tcp_max_syn_backlog指定，表示处于 SYN_RECV 状态的队列<br/>ACCEPT队列（全连接队列）：由listen()函数的第二个参数 backlog 指定，内核硬限制由 net.core.somaxconn 限制，即实际的值由min(backlog,somaxconn) 来决定。表示已完成连接的队列，等待被 accept系统调用取走。<br/>原文链接：https://blog.csdn.net/Tanswer_/article/details/78375317<br/><br/><a href="https://img-blog.csdn.net/20171028140904098?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGFuc3dlcl8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" target="_blank"><img src="https://img-blog.csdn.net/20171028140904098?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvVGFuc3dlcl8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0" width="367"/></a><br/><br/>cat /proc/sys/net/ipv4/tcp_max_syn_backlog <br/>65535<br/>cat /proc/sys/net/core/somaxconn<br/>65535
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10276/</link>
<title><![CDATA[swoole实现redis连接池CoroutineChannel核心原理。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Fri, 30 Aug 2019 08:24:43 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10276/</guid> 
<description>
<![CDATA[ 
	Channel-&gt;push ：当队列中有其他协程正在等待pop数据时，自动按顺序唤醒一个消费者协程。当队列已满时自动yield让出控制器，等待其他协程消费数据<br/>Channel-&gt;pop：当队列为空时自动yield，等待其他协程生产数据。消费数据后，队列可写入新的数据，自动按顺序唤醒一个生产者协程。<br/>Coroutine&#92;Channel使用本地内存，不同的进程之间内存是隔离的。只能在同一进程的不同协程内进行push和pop操作<br/>Coroutine&#92;Channel在2.0.13或更高版本可用<br/><br/>作者：逸宸a<br/>链接：https://www.jianshu.com/p/ed71cb92050d<br/>来源：简书<br/>简书著作权归作者所有，任何形式的转载都请联系作者获得授权并注明出处。<br/><br/><textarea name="code" class="php" rows="15" cols="100">
cat pooldemo.php 
&lt;?php
use &#92;Swoole&#92;Coroutine&#92;Channel;
$chan = new Channel();
go(function () use ($chan) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;我是第一个协程，等待3秒内有push就执行返回&quot; . PHP_EOL;
&nbsp;&nbsp;&nbsp;&nbsp;$p = $chan-&gt;pop(2);#1
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;pop返回结果&quot; . PHP_EOL;
&nbsp;&nbsp;&nbsp;&nbsp;var_dump($p);
&#125;);
go(function () use ($chan) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;co::sleep(1);#2
&nbsp;&nbsp;&nbsp;&nbsp;$chan-&gt;push(1);
&#125;);
echo &quot;main&quot; . PHP_EOL;





1处代码会首先执行，然后遇到pop(),因为channel还是空，会等待2s。此时协程会让出cpu,跳到第二个协程执行，然后#2出睡眠1秒，push变量1进去channel后返回#1处继续执行，成功取车通过中刚push的值1.运行结果为：
我是第一个协程，等待3秒内有push就执行返回
main
pop返回结果
/data/www/xiangdong.coro.swoole.com.cn/pooldemo.php:8:
int(1)

设置超过2秒的情况：
如果把#2处的睡眠时间换成大于pop()的等待时间，结果是：#php pooldemo.php 
我是第一个协程，等待3秒内有push就执行返回
main
pop返回结果
/data/www/xiangdong.coro.swoole.com.cn/pooldemo.php:8:
bool(false)
</textarea><br/><br/>来自：https://www.jianshu.com/p/ed71cb92050d<br/>https://www.jianshu.com/p/ed71cb92050d
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10250/</link>
<title><![CDATA[[实践OK]swoole4.4.1协程和通道实现并发访问三个网站。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Mon, 22 Jul 2019 09:03:23 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10250/</guid> 
<description>
<![CDATA[ 
	背景：关于Go的一协程和通道，PHP也是可以的。<br/><br/>实践中发现swoole去获取微信授权，在单队列网卡和多队列（2个物理核心，8逻辑CPU）的一个情况：<br/>单队列：<br/>8CPU8G：1000并发。<br/>两队列：<br/>8CPU8G：10000并发1W的TPS。<br/><br/>#ls /sys/class/net/enp0s3/queues/<br/>rx-0&nbsp;&nbsp;tx-0<br/><br/>Top的Cache有点多：<br/>7111104 buff/cache<br/><br/>队列来自：https://jackxiang.com/post/10079/<br/><br/><br/>技术：<br/>也就是说三次访问以最长那个，在一些微信请求时以PHP-FPM进行阻塞时，80进程也就400个请求，用这个swoole的请求也就不存在这个问题，可以实现同时发出curl请求，而不是卡在那儿。<br/><br/>也即使是Mysql的访问，用协程，如果一次卡20秒，那么影响也就那一个请求，而不是所有的后面请求就排队等待，这也就是它的优势。<br/><br/>其实现方式，应该是用socket的句柄结合Epoll的事件驱动经过reactor的挂起和唤醒，用到系统的内核进行通知，性能是很不错的。也就是说：<br/>1）必须开端口。<br/>2）那个句柄数要设置大一些才行，一般设置个10万左右。<br/>3）协程对内存的要求较高，内存大一些好。<br/><br/>系统三大杀手，一是内存拷贝（PHP内核支持写时拷贝）、二是系统调用、进程线程切换，而协程经过测试PHP切换一次150纳秒，而Go得160纳秒。<br/><br/>========================================================================================<br/>#cat&nbsp;&nbsp;curl.php&nbsp;&nbsp; <br/><br/><textarea name="code" class="php" rows="15" cols="100">&nbsp;&nbsp; 
&lt;?php
$server = new Swoole&#92;Http&#92;Server(&#039;127.0.0.1&#039;,8000);
$server-&gt;on(&quot;Request&quot;,function($req,$resp)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;$chan = new Chan();
&nbsp;&nbsp;&nbsp;&nbsp;go(function () use ($chan)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c = new Co&#92;Http&#92;Client(&quot;www.baidu.com&quot;,443,true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c-&gt;get(&#039;/index.php&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $chan-&gt;push($c-&gt;body);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;go(function () use ($chan)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c = new Co&#92;Http&#92;Client(&quot;www.taobao.com&quot;,443,true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c-&gt;get(&#039;/index.php&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $chan-&gt;push($c-&gt;body);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;go(function () use ($chan)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c = new Co&#92;Http&#92;Client(&quot;www.sina.com.cn&quot;,443,true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $c-&gt;get(&#039;/index.php&#039;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $chan-&gt;push($c-&gt;body);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;);
&nbsp;&nbsp;&nbsp;&nbsp;for($i = 0; $i &lt; 3;$i++)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$resp-&gt;write($chan-&gt;pop());
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;$resp-&gt;end();
&#125;);

$server-&gt;start();
</textarea><br/><br/>php curl.php<br/>PHP Fatal error:&nbsp;&nbsp;Swoole&#92;Coroutine&#92;Http&#92;Client::__construct(): need to use `--enable-openssl` to support ssl when compiling swoole. in /data/www/coding.jackxiang.com/curl.php on line 6<br/>[2019-07-22 16:53:17 $4830.0]&nbsp;&nbsp; WARNING swManager_check_exit_status: worker#0 abnormal exit, status=255, signal=0<br/><br/>curl 127.0.0.1:8000<br/>curl: (52) Empty reply from server<br/><br/>重新编译：<br/><textarea name="code" class="php" rows="15" cols="100">
phpize
./configure --with-php-config=/usr/local/php/bin/php-config --enable-coroutine --enable-openssl&nbsp;&nbsp;
make &amp;&amp; make install
</textarea><br/><br/><br/>configure: WARNING: unrecognized options: --enable-coroutine ，最新版本好像把这个给去了。<br/><br/>/usr/local/src/swoole-src-4.4.1/include/swoole.h:591:25: fatal error: openssl/ssl.h: No such file or directory<br/> #include &lt;openssl/ssl.h&gt;<br/><br/>还是不行，参考了一下：<br/>http://www.21yunwei.com/archives/5196<br/><br/>重新phpize再来一次就好了，估计是和phpize生成的configure有关吧。<br/><br/>mv&nbsp;&nbsp;/usr/local/php/lib/php/extensions/no-debug-non-zts-20170718/swoole.so /usr/local/php/ext/.<br/>mv: overwrite ‘/usr/local/php/ext/./swoole.so’? y<br/>启动服务端：<br/>#php curl.php <br/>strace -ff -o /tmp/s.txt -tt php curl.php <br/><br/>连接测试：<br/>curl 127.0.0.1:8000<br/><br/>得到三个网站的返回。<br/><br/><br/>
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10156/</link>
<title><![CDATA[ [转]【swoole4.0】一次qps提升之旅(一)]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Tue, 09 Apr 2019 02:21:47 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10156/</guid> 
<description>
<![CDATA[ 
	背景：PHP在跨版本升级时一些扩展没跟上，跨的步子不是小而是不够大，跟不上的问题只好swoole来帮其迈步大一些，但是毕竟相关配套还是没有来得及跟上，有观望的，有踟蹰不前的，有换Go的，总之，这个过程是艰难，王导的这篇文章就是一个对swoole的性能再次作优化的一个不错的分享,君子身非异也，善假于物也，说白了就是工具配套很重要的，希望周边的扩展能跟上，特转之。<br/><br/>源起<br/>最近基于swoole的一个mvc开发框架做了一个项目，完成之后对其中一个接口例行做了一次压测，本机上得到qps是3600，由于接口功能比较简单，所以又花了点时间用beego和spring boot实现了相同的功能，也压测了一下，最终对比如下：<br/><br/>swoole:&nbsp;&nbsp;3600qps<br/>beego:&nbsp;&nbsp; 2200 qps<br/>spring:&nbsp;&nbsp; 600qps<br/><br/>（ps: 无意比较优劣，应该是用beego和spring boot的姿势不对）<br/><br/>swoole的结果符合预期，后来经过一翻折腾(加了一些逻辑，完善了一些底层框架代码)，再一压这个接口，qps下降到了2300<br/><br/>真是一顿操作猛如虎，性能下降35%啊<br/><br/>优化<br/>做为一个有追求的phper，这是不能忍的，必需找到原因并解决之，但光喊口号是不行的，必需有方法，一般我们会通过几种方式分析：<br/>日志法：通过各种日志，查看耗时，找出相应的问题，但这种方法有几个缺点：<br/>粒度太粗，不好控制<br/>侵入性太强，需要人工打点<br/>性能指标不够，只能分析出大致的耗时，但不能分区i/o, cpu时间乖<br/>xdebug：是我认为目前最牛逼的性能分析工具，可以无侵入式的详细的记录完整的调用链，唯一的遗憾是与swoole不兼容<br/>xhprof: facebook出口的一款性能分析工具，简单易用，问题是：后期不维护了，对现在的php版本以及swoole支持度都不好<br/>第三方的apm工具: 不可控，也不如前面2位，对swoole支持也不好<br/>除了打日志，好像在swoole下陷入的僵局了，一翻寻觅，发现了一个网站：https://tideways.com/，维护并持续更新xhprof，使之能支持php7，又一翻折腾，发现也支持在swoole下跑<br/><br/>安装 tideways_xhprof<br/><br/>github: https://github.com/shenzhe/php-xhprof-extension<br/>clone代码到本地<br/>执行：<br/> phpize<br/> ./configure<br/> make<br/> make install<br/><br/>标准的安装过程，产生tideways_xhprof.so，加入到php.ini中<br/><br/>判断有没有安装成功：<br/>php -m &#124;grep xhprof<br/>输出<br/>tideways_xhprof, 表示安装成功<br/><br/>使用 tideways_xhprof<br/>也比较简单<br/>在onRequest回调最开始一行输入：<br/>tideways_xhprof_enable(TIDEWAYS_XHPROF_FLAGS_MEMORY<br/>&nbsp;&nbsp;&#124; TIDEWAYS_XHPROF_FLAGS_CPU);<br/>表示开启分析，<br/><br/>中间执行你的业务逻辑<br/><br/>在最后一行输入<br/>file_put_contents(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#039;/tmp/xhprof/&#039; . uniqid() . &#039;.msg-api.xhprof&#039;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;serialize(tideways_xhprof_disable())<br/>);<br/>把分析的结果存入到文件中，以待分析<br/>其中：<br/>&#039;/tmp/xhprof/&#039; . uniqid() . &#039;.msg-api.xhprof&#039;<br/>是最终分析文件的地址，可自行修改<br/><br/>然后执行你的接口，最后会在 /tmp/xhprof 文件夹下看到如下的文件：<br/><a href="https://mmbiz.qpic.cn/mmbiz_png/LHDiahSVnXhv7RIhE32icGiaCnx7uBicR84LiaMb7fknqq9u3AD17icvY2ru9j20UndbciaLpLAicX2VYR94EqrPQ3UsXA/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" target="_blank"><img src="https://mmbiz.qpic.cn/mmbiz_png/LHDiahSVnXhv7RIhE32icGiaCnx7uBicR84LiaMb7fknqq9u3AD17icvY2ru9j20UndbciaLpLAicX2VYR94EqrPQ3UsXA/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>这些文件记录的就是这个接口整体的分析数据<br/><br/>找出最新的文件，用vim打开一看：<br/><a href="https://mmbiz.qpic.cn/mmbiz_png/LHDiahSVnXhv7RIhE32icGiaCnx7uBicR84LibG10P4PM0gla8NkdYNwqSEQiaxb51UUWxJH62Tnrwsfaqo0olHXg57A/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" target="_blank"><img src="https://mmbiz.qpic.cn/mmbiz_png/LHDiahSVnXhv7RIhE32icGiaCnx7uBicR84LibG10P4PM0gla8NkdYNwqSEQiaxb51UUWxJH62Tnrwsfaqo0olHXg57A/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>肉眼肯定是没法看，这就需要借助可视化的工具了：<br/><br/><br/><br/>可视化 tideways_xhprof<br/><br/>由于输出的文件格式和之前的xhprof完全一样，所以我这边直接借助了原本xhprof提供的工具 <br/><br/>github：https://github.com/phacility/xhprof<br/><br/><br/><br/>最终上面的分析文件可视化后如下：<br/>https://mmbiz.qpic.cn/mmbiz_png/LHDiahSVnXhs4fa6cxh7fpapG6H17PNhg6IlUhPtFdfd2Owb70WRtt31Ecg4gRTJODxXgt4xjeSRtOqerNcVvoA/640?wx_fmt=png&amp;tp=webp&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1<br/><br/>下一篇，将详细介绍如何安装xhprof可视化工具，以及我们要看什么指标，怎么通过这些指标来指导来做优化，并最终提升的程序的性能<br/><br/><br/><br/>查看原文，可获取我修改版的tideways_xhprof，增加了两个方法，以支持RINIT和RSHUTDOWN中做的一些事情：<br/><br/>tideways_xhprof_swoole_init();<br/><br/>tideways_xhprof_swoole_end();<br/>这样可以更好的支持swoole,&nbsp;&nbsp;readme里有介绍使用方法<br/><br/>原文：https://mp.weixin.qq.com/s/uekLWuXz5i2OBDsnYhwShw
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10139/</link>
<title><![CDATA[SwooleOne框架混合协议研究。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Sat, 30 Mar 2019 07:30:22 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10139/</guid> 
<description>
<![CDATA[ 
	这个one能实现那个硬件tcp和手机的websocket的混合通讯嘛，说白了就是那个手机关灯，手机上websocket发给硬件，硬件收到指令后完成一个关灯动作后再返回，告诉用户已经关灯的例子。￼<br/><br/><br/>可以<br/>混合协议通讯<br/><br/>手册：<br/>https://github.com/lizhichao/one-demo/blob/master/README.md#%E5%90%84%E7%A7%8D%E6%B7%B7%E5%90%88%E5%8D%8F%E8%AE%AE%E4%B9%8B%E9%97%B4%E7%9B%B8%E4%BA%92%E9%80%9A%E8%AE%AF%E5%88%97%E5%AD%90<br/><br/>代码：<br/>https://github.com/lizhichao/one-demo/tree/master/App/Test/MixPro<br/><br/><br/>混合协议配置文件：<br/>https://github.com/lizhichao/one-demo/blob/master/App/Config/test_all.php<br/><br/>$this-&gt;global_data-&gt;bindId($request-&gt;fd, $name); #这个bindld是在哪儿？<br/>https://github.com/lizhichao/one-demo/blob/master/App/GlobalData/Data.php
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10040/</link>
<title><![CDATA[[实践OK]centos 6升级 GCC 到4.8 ，GCC 4.8 or later required。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Wed, 09 Jan 2019 08:27:31 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10040/</guid> 
<description>
<![CDATA[ 
	CentOS7升级GCC版本：<a href="https://jackxiang.com/post/10700/" target="_blank">https://jackxiang.com/post/10700/</a><br/><br/>想打包一个swoole最新版，出现 问题如下：<br/><textarea name="code" class="php" rows="15" cols="100">
 cc -I. -I/root/rpmbuild/BUILD/swoole-src-4.2.12 -DPHP_ATOM_INC -I/root/rpmbuild/BUILD/swoole-src-4.2.12/include -I/root/rpmbuild/BUILD/swoole-src-4.2.12/main -I/root/rpmbuild/BUILD/swoole-src-4.2.12 -I/usr/local/php/include/php -I/usr/local/php/include/php/main -I/usr/local/php/include/php/TSRM -I/usr/local/php/include/php/Zend -I/usr/local/php/include/php/ext -I/usr/local/php/include/php/ext/date/lib -I/root/rpmbuild/BUILD/swoole-src-4.2.12 -I/root/rpmbuild/BUILD/swoole-src-4.2.12/include -I/root/rpmbuild/BUILD/swoole-src-4.2.12/thirdparty/hiredis -DHAVE_CONFIG_H -Wall -pthread -g -O2 -c /root/rpmbuild/BUILD/swoole-src-4.2.12/src/core/array.c&nbsp;&nbsp;-fPIC -DPIC -o src/core/.libs/array.o
In file included from /root/rpmbuild/BUILD/swoole-src-4.2.12/include/swoole.h:174,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from /root/rpmbuild/BUILD/swoole-src-4.2.12/src/core/array.c:17:
./swoole_config.h:22:2: error: #error &quot;GCC 4.8 or later required.&quot;
make: *** [src/core/array.lo] Error 1
</textarea><br/><br/>解决办法：<br/>安装最新版本的swoole 提示<br/><br/>pecl install swolle <br/>...<br/>GCC 4.8 or later required.<br/>首先想到的时候yum更新gcc<br/><br/>yum install gcc<br/>Package gcc-4.4.7-23.el6.x86_64 already installed and latest version<br/>Nothing to do<br/>已经是最新版本了，怎么办，只有找其它源了<br/><br/>curl -Lks http://www.hop5.in/yum/el6/hop5.repo &gt; /etc/yum.repos.d/hop5.repo<br/>yum install gcc gcc-g++<br/>安装成功<br/><br/>gcc -v<br/>gcc version 4.8.2 20131212 (Red Hat 4.8.2-8) (GCC)<br/><br/><br/>来自：https://my.oschina.net/2688/blog/2933883
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9712/</link>
<title><![CDATA[[实践OK]redis的brpop简单使用,brpop的意思是在消息队列尾阻塞地取出消息，参数0表示一直阻塞下去直到有消息在msg这个list中，我们可以指定一个数字代表过期时间。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Wed, 11 Apr 2018 06:41:48 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9712/</guid> 
<description>
<![CDATA[ 
	Q:这个brpop后面的2参数啥意思？是想模拟多个消费者吗？那个yii不也有类似消费者和swoole这个例子的差距不对差别在哪鹅？<br/>Swoole-2.1.2 进程池模块的使用：http://mp.weixin.qq.com/s?__biz=MzI0MjEwMDMzNQ==&amp;mid=2652517441&amp;idx=1&amp;sn=06909bb58cc4c0f3ade589a005ed6e84&amp;chksm=f2efe541c5986c5741aa240e9a4daaab47c542b325a0042c4fbd5094ded48221035d90003fe1&amp;mpshare=1&amp;scene=1&amp;srcid=04119CY2J0y8Az2isPm9UKyL#rd<br/><br/><br/>redis-cli <br/>127.0.0.1:6379&gt; del list1 list2<br/>(integer) 0<br/>127.0.0.1:6379&gt; rpush list1 a b c<br/>(integer) 3<br/>127.0.0.1:6379&gt; brpop list1 list2 0<br/>1) &quot;list1&quot;<br/>2) &quot;c&quot;<br/><br/><br/><br/>brpop的效果吧，首先模拟一个消息的“生产者”<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r = new Redis();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r-&gt;connect(&quot;127.0.0.1&quot;, 6379);&nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r-&gt;lpush(&quot;msg&quot;,&quot;Hello ciaos&quot;);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r-&gt;lpush(&quot;msg&quot;,&quot;Hello penjin&quot;);&nbsp;&nbsp;
?&gt;&nbsp;&nbsp;
然后模拟一个消息的消费者，而redis-server则充当中间的消息队列（我这里当然用的是redis的list类型）
[codes=php]
&lt;?php&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r = new Redis();&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$r-&gt;connect(&quot;127.0.0.1&quot;, 6379);&nbsp;&nbsp;
&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$res = $r-&gt;brpop(&quot;msg&quot;,0);&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var_dump($res);&nbsp;&nbsp;
?&gt;&nbsp;&nbsp;
</textarea><br/>很简单，brpop的意思是在消息队列尾阻塞地取出消息，参数0表示一直阻塞下去直到有消息在msg这个list中，我们可以指定一个数字代表过期时间。首先运行消费者，可以看到程序阻塞了，然后运行“生产者”，则消费者输出了消息如下：<br/><textarea name="code" class="php" rows="15" cols="100">
php consumer.php&nbsp;&nbsp;
</textarea><br/>array(2) &#123;&nbsp;&nbsp;<br/>&nbsp;&nbsp;[0]=&gt;&nbsp;&nbsp;<br/>&nbsp;&nbsp;string(3) &quot;msg&quot;&nbsp;&nbsp;<br/>&nbsp;&nbsp;[1]=&gt;&nbsp;&nbsp;<br/>&nbsp;&nbsp;string(11) &quot;Hello ciaos&quot;&nbsp;&nbsp;<br/>&#125;&nbsp;&nbsp;<br/><br/>lpush操作和brpop操作也保证了队列的先进先出，如果用blpop则会看到输出的是&quot;Hello penjin&quot;(第二条消息)。<br/>其中brpop还可以指定监测多个消息队列，直到有任意一个消息队列中有待处理消息时阻塞返回，感觉还是比较简单易用的。redis的list消息队列没有优先级的概念，所有消息都只能先进先出或者后进先出，要实现优先级，可以考虑使用set数据结构。
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9381/</link>
<title><![CDATA[根本就没有什么所谓的开源商业模式之某赞。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Wed, 26 Jul 2017 06:37:58 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9381/</guid> 
<description>
<![CDATA[ 
	文章链接：http://mp.weixin.qq.com/s/w4nJrH6RzQ7dg9cd6cwazw<br/>现实分析：<br/>此文里提到的Interix 和前几个月某赞从Swoole2.0仓库默默拉出一个分支，“美其名曰”因Swoole文档太烂边吐槽Swoole，一边火速以公司研发之名“自立门户”之既成事实，Swoole顾问试问那么差的文档某赞不积极贡献是咋学会的呢，作出了自建社区的举动和行动？显然背后有不可名状的目的，首先，某赞没尊重代码作者、辱没开源意识形态、对回馈开源的态度极其简单粗暴乃至蛮横。其次，某赞违背了自由软件开发的工程经济学。借助其公司团队根据自己的产品和服务，从Swoole的仓库打出分支，并尝试发展自己的协作社区，从而使这家公司获得了很多的益处（技术影响力/品牌形象）进而违背Apache2宽松协议。最后，某赞的这种行为和当年的Interrix一样的情形，给予上游开源的Swoole项目，自己搞了一个分支，这就意味着某赞无法获得Swoole主干的新功能和新的Bug修复，自己搞的所谓更高效的时间轮不开放变闭源了。鉴于此，Rango兄弟最近修改Swoole发行协议为PHP协议，与Swoole的上游PHP的协议保持高度一致，其目的就是禁止商业公司fork分支拿Swoole做宣传，保护开源社区不被商业公司利用。Swoole顾问希望某赞不要在开源的“邪路”上越走越远，积极拥抱正回馈和贡献服务之态度修正航道回开源的主航道上来，进一步促进自由软件开发的工程经济学，EOF<br/><br/><br/>
]]>
</description>
</item>
</channel>
</rss>