<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://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://jackxiang.com/post//</link>
<title><![CDATA[关于异步任务队列之PHP使用swoole来实现实时异步任务队列。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Php/Js/Shell/Go]]></category>
<pubDate>Wed, 27 Apr 2016 01:50:51 +0000</pubDate> 
<guid>http://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	背景：关于PHP的异步回调啥的，其实PHP这种语言的运行机制想优雅实现是不可能的，有一个叫swoole的扩展实现这个队列的处理是很不错的，之前有张宴兄弟写过一个叫https的队列处理（基于libevent），后面有韩天峰兄弟写的swoole，更注重了异步IO实现对CPU的IO的吃满（基于自己编写的epoll加队列链表内存分配一堆东西，反正我是看过没看明白有空再研究），但是，作为swoole的粉丝兼顾问，异步问题在PHP业界的一个需求量还是蛮大的，尤其是日志异步写、url访问、邮件异步发、跨机房db特殊的小同步、审核异步队列、框架底层对接口访问排查错误的db和cache接口查询及返回，这些目前对于大并发网站都是需要异步来解决的，但是异步归异步，回调这块也实现异步回调（真大并发想知道结果可能阻塞了PHP进程产生进程等待异步返回而新来的连接没法及时处理的php-fpm进程性雪崩），在实际运用中常规处理办法是开一个新的端口，下面的swoole也是开了新的端口来处理，于httpsqs不同在于swoole可以把简单的curl啥的逻辑也可封装里面，在httpsqs里只是纯队列，一个投递进来，再起一个php的daemon进行读取队列，因为如果真是繁忙，导致异步处理返回慢，这个等待也是太漫长，我觉得看具体业务而看要不要等待，在实际中异步和队列大都用于抛数据以及解耦，swoole在这块不光有了异步还有异步回调，所以，最大限度的解决了上面这些场景，先抄一篇文章再说，有空再研究研究其实现，假如能看懂的话：-），异步回调这块如果有明白的可以留言给我，谢谢。<br/>————————————————————————————————————————————————————————————————————————<br/>关于异步任务队列<br/><br/>用户打开了我们的网站。他要做的就是勾选需要发邮件的代理商列表，然后把结算邮件发出去。 <br/>假如我们需要发1封邮件，我们写个函数执行即可。考虑到网络可能会稍微有点延迟，但是是可以接受的，用户会乖乖等你的网页发完邮件了再关闭网页。 <br/>假如我们要发布10封邮件，用一个for循环，循环10遍执行发邮件操作。这时候，也许10倍的网络延迟会让用户稍微有点不耐烦，但勉强可以等吧。 <br/>假如要发100封邮件，for循环100遍，用户直接揭竿而起，什么破网站！ <br/>但实际上，我们很可能有超过1万的邮件。怎么处理这个延迟的问题？ <br/>答案就是用异步。把“发邮件”这个操作封装，然后后台异步地执行1万遍。这样的话，用户提交网页后，他所等待的时间只是“把发邮件任务请求推送进队列里”的时间。而我们的后台服务将在用户看不见的地方跑。 <br/>在实现“异步队列”这点上，有人采用mysql表或者redis来存放待发送的邮件，然后，每分钟定时读取待发送列表，然后处理。这便是定时异步任务队列。但当前提交的任务要一分钟后才能执行，在某些实时性要求应用场景里还是不快。有些场景要求，只有一提交任务，便马上执行，但用户不需要等待返回结果。 <br/>在云平台SAE和BAE上，都有taskqueue服务来解决上面的问题。而如果是自己假设服务器，则如何解决？本文将探讨用php扩展swoole实现实时异步任务队列的方案。<br/><br/>安装swoole<br/><br/>pecl 安装: <br/>pecl install swoole<br/><br/>看命令行提示，如果它提示说没有写php.ini，则自己手动在PHP.ini后面加上： <br/>extension = &quot;swoole.so&quot;<br/><br/>服务端<br/><br/>在打算放置脚本的目录（你也可以自行新建）新建Server.php，代码如下：<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
class Server
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;private $serv;
&nbsp;&nbsp;&nbsp;&nbsp;public function __construct() &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv = new swoole_server(&quot;0.0.0.0&quot;, 9501);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv-&gt;set(array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;worker_num&#039; =&gt; 1,&nbsp;&nbsp; //一般设置为服务器CPU数的1-4倍
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;daemonize&#039; =&gt; 1,&nbsp;&nbsp;//以守护进程执行
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;max_request&#039; =&gt; 10000,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;dispatch_mode&#039; =&gt; 2,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;task_worker_num&#039; =&gt; 8,&nbsp;&nbsp;//task进程的数量
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;task_ipc_mode &quot; =&gt; 3 ,&nbsp;&nbsp;//使用消息队列通信，并设置为争抢模式
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&quot;log_file&quot; =&gt; &quot;log/taskqueueu.log&quot; ,//日志
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv-&gt;on(&#039;Receive&#039;, array($this, &#039;onReceive&#039;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// bind callback
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv-&gt;on(&#039;Task&#039;, array($this, &#039;onTask&#039;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv-&gt;on(&#039;Finish&#039;, array($this, &#039;onFinish&#039;));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;serv-&gt;start();
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;public function onReceive( swoole_server $serv, $fd, $from_id, $data ) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Get Message From Client &#123;$fd&#125;:&#123;$data&#125;n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// send a task to task worker.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$serv-&gt;task( $data );
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;public function onTask($serv,$task_id,$from_id, $data) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$array = json_decode( $data , true );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($array[&#039;url&#039;]) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $this-&gt;httpGet( $array[&#039;url&#039;] , $array[&#039;param&#039;]&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;public function onFinish($serv,$task_id, $data) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Task &#123;$task_id&#125; finishn&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//echo &quot;Result: &#123;$data&#125;n&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;protected function httpGet($url,$data)&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($data) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$url .=&#039;?&#039;.http_build_query($data) ;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$curlObj = curl_init();&nbsp;&nbsp;&nbsp;&nbsp;//初始化curl，
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($curlObj, CURLOPT_URL, $url);&nbsp;&nbsp; //设置网址
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1);&nbsp;&nbsp;//将curl_exec的结果返回
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($curlObj, CURLOPT_SSL_VERIFYPEER, FALSE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($curlObj, CURLOPT_SSL_VERIFYHOST, FALSE);&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_setopt($curlObj, CURLOPT_HEADER, 0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //是否输出返回头信息
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$response = curl_exec($curlObj);&nbsp;&nbsp; //执行
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;curl_close($curlObj);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//关闭会话
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $response;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;
$server = new Server();
</textarea><br/><br/>由于服务端是异步、常驻内存的，因此必须通过命令行来启动。在命令行执行以上代码以启动服务 <br/>php Server.php <br/>执行完毕后关闭命令行窗口即可。服务会在后台以守护进程运行<br/><br/>客户端<br/><br/>启动服务后，让我们看看如何调用服务。新建测试文件Client_test.php <br/>代码如下：<br/><textarea name="code" class="php" rows="15" cols="100">
&lt;?php
class Client
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;private $client;
&nbsp;&nbsp;&nbsp;&nbsp;public function __construct() &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;client = new swoole_client(SWOOLE_SOCK_TCP);
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;public function connect() &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if( !$this-&gt;client-&gt;connect(&quot;127.0.0.1&quot;, 9501 , 1) ) &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Connect Error&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data = array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;url&quot; =&gt;&nbsp;&nbsp;&quot;http://192.168.10.19/send_mail&quot; ,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;param&quot; =&gt; array(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;username&quot;=&gt;&#039;test&#039;,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;password&quot; =&gt; &#039;test&#039;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$json_data = json_encode($data);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this-&gt;client-&gt;send( $json_data );
&nbsp;&nbsp;&nbsp;&nbsp;&#125;
&#125;
$client = new Client();
$client-&gt;connect();
</textarea><br/><br/>在上面代码中，url即为任务所在地址，param为所需传递参数。 <br/>保存好代码，在命令行或者浏览器中执行Client_test.php,便实现了异步任务队列。你所填写的URL，将会在每次异步任务被提交后，以HTTP GET的方式异步执行。<br/><br/>查看与关闭<br/><br/>swoole好像没有很便捷的关闭方式。所以只能直接通过关闭进程来关闭。 <br/>查看命令： <br/>ps -ef &#124; grep php <br/>结束单个进程： <br/>kill -9 &#123;进程号&#125; <br/>结束所有进程的命令： <br/>killall -9 php<br/><br/>摘自第七星尘的博客：http://blog.star7th.com/2016/01/1905.html
]]>
</description>
</item><item>
<link>http://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论] 关于异步任务队列之PHP使用swoole来实现实时异步任务队列。]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>