PHP使用swoole來實現實時異步任務隊列


轉載來自第七星塵的技術博客《PHP使用swoole來實現實時異步任務隊列》

關於異步任務隊列

用戶打開了我們的網站。他要做的就是勾選需要發郵件的代理商列表,然后把結算郵件發出去。
假如我們需要發1封郵件,我們寫個函數執行即可。考慮到網絡可能會稍微有點延遲,但是是可以接受的,用戶會乖乖等你的網頁發完郵件了再關閉網頁。
假如我們要發布10封郵件,用一個for循環,循環10遍執行發郵件操作。這時候,也許10倍的網絡延遲會讓用戶稍微有點不耐煩,但勉強可以等吧。
假如要發100封郵件,for循環100遍,用戶直接揭竿而起,什么破網站!
但實際上,我們很可能有超過1萬的郵件。怎么處理這個延遲的問題?
答案就是用異步。把“發郵件”這個操作封裝,然后后台異步地執行1萬遍。這樣的話,用戶提交網頁后,他所等待的時間只是“把發郵件任務請求推送進隊列里”的時間。而我們的后台服務將在用戶看不見的地方跑。
在實現“異步隊列”這點上,有人采用mysql表或者redis來存放待發送的郵件,然后,每分鍾定時讀取待發送列表,然后處理。這便是定時異步任務隊列。但當前提交的任務要一分鍾后才能執行,在某些實時性要求應用場景里還是不快。有些場景要求,只有一提交任務,便馬上執行,但用戶不需要等待返回結果。
在雲平台SAE和BAE上,都有taskqueue服務來解決上面的問題。而如果是自己假設服務器,則如何解決?本文將探討用php擴展swoole實現實時異步任務隊列的方案。

安裝swoole

pecl 安裝:
pecl install swoole

看命令行提示,如果它提示說沒有寫php.ini,則自己手動在PHP.ini后面加上:
extension = "swoole.so"

服務端

在打算放置腳本的目錄(你也可以自行新建)新建Server.php,代碼如下:

<?php class Server { private $serv; public function __construct() { $this->serv = new swoole_server("0.0.0.0", 9501); $this->serv->set(array( 'worker_num' => 1, //一般設置為服務器CPU數的1-4倍 'daemonize' => 1, //以守護進程執行 'max_request' => 10000, 'dispatch_mode' => 2, 'task_worker_num' => 8, //task進程的數量 "task_ipc_mode " => 3 , //使用消息隊列通信,並設置為爭搶模式 //"log_file" => "log/taskqueueu.log" ,//日志 )); $this->serv->on('Receive', array($this, 'onReceive')); // bind callback $this->serv->on('Task', array($this, 'onTask')); $this->serv->on('Finish', array($this, 'onFinish')); $this->serv->start(); } public function onReceive( swoole_server $serv, $fd, $from_id, $data ) { //echo "Get Message From Client {$fd}:{$data}n"; // send a task to task worker. $serv->task( $data ); } public function onTask($serv,$task_id,$from_id, $data) { $array = json_decode( $data , true ); if ($array['url']) { return $this->httpGet( $array['url'] , $array['param'] ); } } public function onFinish($serv,$task_id, $data) { //echo "Task {$task_id} finishn"; //echo "Result: {$data}n"; } protected function httpGet($url,$data){ if ($data) { $url .='?'.http_build_query($data) ; } $curlObj = curl_init(); //初始化curl, curl_setopt($curlObj, CURLOPT_URL, $url); //設置網址 curl_setopt($curlObj, CURLOPT_RETURNTRANSFER, 1); //將curl_exec的結果返回 curl_setopt($curlObj, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curlObj, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curlObj, CURLOPT_HEADER, 0); //是否輸出返回頭信息 $response = curl_exec($curlObj); //執行 curl_close($curlObj); //關閉會話 return $response; } } $server = new Server(); 

由於服務端是異步、常駐內存的,因此必須通過命令行來啟動。在命令行執行以上代碼以啟動服務
php Server.php
執行完畢后關閉命令行窗口即可。服務會在后台以守護進程運行

客戶端

啟動服務后,讓我們看看如何調用服務。新建測試文件Client_test.php
代碼如下:

<?php class Client { private $client; public function __construct() { $this->client = new swoole_client(SWOOLE_SOCK_TCP); } public function connect() { if( !$this->client->connect("127.0.0.1", 9501 , 1) ) { echo "Connect Error"; } $data = array( "url" => "http://192.168.10.19/send_mail" , "param" => array( "username"=>'test', "password" => 'test' ) ); $json_data = json_encode($data); $this->client->send( $json_data ); } } $client = new Client(); $client->connect(); 

在上面代碼中,url即為任務所在地址,param為所需傳遞參數。
保存好代碼,在命令行或者瀏覽器中執行Client_test.php,便實現了異步任務隊列。你所填寫的URL,將會在每次異步任務被提交后,以HTTP GET的方式異步執行。

查看與關閉

swoole好像沒有很便捷的關閉方式。所以只能直接通過關閉進程來關閉。
查看命令:
ps -ef | grep php
結束單個進程:
kill -9 {進程號}
結束所有進程的命令:
killall -9 php


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM