前段時間在開發一個量化交易系統,這是一個類似股票交易軟件的系統:股票價格變化後要實時在終端(APP)的行情價格頁面實時更新,如果用戶是在持倉頁面,還要計算持倉盈虧及預付款比例,因爲有一個強制平倉機制(當預付款比較低於30%時系統要自動觸發強制平倉),因爲行情波動非常快(有些產品一秒鐘內價格會變化五六次),所以當某個產品的價格變化時,要觸發一系統的行情推送(通過長連接)及盈虧計算操作。
因爲價格變動非常快,如果使用同步操作的話,很容易造成阻塞,所以用異步消息隊列是比較好的選擇,在網上查了一番,決定用resque來實現,試用了一下,發現網上所謂的resque教程大都是將它的demo代碼講解了一遍,坑很多,所以把我試用過程中遇到的問題統一做個記錄,一個是方便同樣正在嘗試使用resque的朋友,二是作爲自己的備忘錄,好,下面正式開始。
Part 1.安裝
網上很多教程的指引還是安裝源chrisboulton/php-resque
版本的,實際上現在最新的版本應該是resque/php-resque
源的, 用composer安裝的方法是,在composer.json
文件中的require節點下添加”resque/php-resque:^1.2
”,
然後執行composer install
即可。
Part2.連接設置了密碼的redis
resque是基於redis的,所以沒有redis是運行不起來的,可能開發者初期沒有考慮到redis有設置了密碼的情況,所以我剛開始看網上的資料是有介紹怎樣解決這個問題的,但我把代碼簽出來後發現Resque::setBackend
的方法是支持傳入auth參數的,於是以爲這個問題已經在目前的版本里解決了,實際上還是不行,如果你的redis裏設置了密碼,建議修改插件目錄下的resque/php-resque/lib/Resque.php
這個文件,大概在68行將創建redis連接的代碼用以下代碼代替可以解決連接redis失敗的問題。
$redis = new Redis();
$redis->connect(self::$redisServer);
$redis->auth(self::$auth);
$redis->select(self::$redisDatabase);
self::$redis = $redis;
修改完後將redis的密碼通過setBackend方法的第三個參數傳入就可以了,示例:
Resque::setBackend('127.0.0.1', 1, \Config::$redis['option']['auth']);
Part3.運行
如果你看了其它網友的經驗分享,你會知道resque有三個角色:Queue、Worker、Job
,Queue負責接收消息隊列,Worker負責任務調度,Job負責執行業務邏輯,用現實生活舉例就是像一個高鐵站一樣,Queue是售票廳、Worker是控制室、Job則是車隊,以下我也分三部分說下這個注意事項:
- Queue:
按照業務邏輯需要,Queue在何時何地執行都可以的,因爲作爲一個消息隊列,肯定要支持動態添加任務進去,有一點要注意的是,如果你的Job類有命名空間,一定要將完整的路徑寫進去,我在這裏卡了一下,以爲在Job類裏通過use引入了這個命名空間即可,但實際上行不通,必須在調用enqueue方法時傳入帶命名空間的路徑才能正常執行,下面是一個示例:
Resque::setBackend('127.0.0.1', 1, \Config::$redis['option']['auth']);
for($i = 1; $i < 10; $i++){
Resque::enqueue('pushMarketPrice', '\site_pc\action\Job', ['newPrice' => 1367.85, 'rate' => 7.09]);
}
- Worker
從demo文件可以看出,Worker就是要加載Job類及bin下的resque文件,但demo裏並不是面向對象的寫法,如果要定義在一個類裏,可以參照以下寫法:
class Worker{
/**
* @router cli work
*/
public function run(){
require "../vendor/resque/php-resque/bin/resque";
}
}
其中,require後面的路徑請修改爲相對你項目執行文件入口的路徑。
- Job
Job類就比較簡單,記着要實現一個perform方法就方法了,另外,demo裏沒有體現的一個細節是在Queue中傳入的參數怎樣獲取,其實很簡單,在perform方法通過$this->args
就能拿到傳入的參數數組,非常方便。
class Job{
public function perform(){
Tools::logToDb('resque', $this->args);
}
}
$this->args
就是你此前在Queue中傳入的自定義參數數組了。
Part4.監控
怎樣判斷resque的狀態(是否在正常運行中)呢?還有如果已經在運行,怎樣重啓?可以通過查看進程的命令來達到這個目的,登錄系統後執行: ps -aux | grep resque
如果resque正在運行中,你看到的界面應該是這樣的:
其中,上圖橢圓形圈中的是進程ID,如果希望停止運行,可以使用kill -9 [進程id]
來殺死進程,紅方框則是進程狀態,正在等待隊列中的任務。一有任務就會執行,至此,這個插件已經在正常運行了。