Laravel隊列的一些細枝末節
因為我崇尚簡單,所以我憎恨一切所謂的「重量級」框架,比如「Laravel」,有時候這種憎恨甚至到了偏執的程度,以至于如果我看到簡歷里寫著 諸如「精通 Laravel」之類的話,那么便會毫不猶豫的 PASS 掉候選人。不過現在我承認有點喜歡「Laravel」了,雖然性能依然是無法回避的短板,但是又有幾個網站能觸及其性能瓶頸呢?而它豐富的組件則實實在在 的節約了開發者大把的時間,比如本文要說的隊列。
在 Laravel 里調用隊列功能是非常簡單的一件事情,詳細介紹參考 官方文檔 :
<?php \Queue::pushOn('mail', new \App\Commands\Mail($data)); ?>
隊列包含了多種驅動:比如 sync、database、redis、beanstalk 等等。其中 sync 乍一看會覺得很奇怪,不過實際上它在開發測試階段超級方便,此外 database、redis 等方案更像是一種模擬,所以說 beanstalk 是目前最合適的選擇。當然, beanstalk 同 nsq 之類的隊列相比,功能上明顯差一個檔次,但是,beanstalk 貴在簡單易用。
Laravel 隊列的消費者有兩種啟動方式,分別是:queue:listen 和 queue:work,我建議你徹底忘記第一種方式,我甚至不理解它為什么存在,因為它不僅低效,而且可能會導致一些莫名其妙的問題,具體可以參考: 一個Laravel隊列引發的報警 。
一旦選擇了 queue:work 方式,需要注意有幾個缺省值如果設置不當會出問題:
- Delay :如果一個任務失敗了,那么它會延遲幾秒后再重新執行。此時間的缺省值為「0」,也就是說不延遲。通常這不是一個好選擇,比如遭遇網絡不穩定,此時一旦失敗,如果不延遲立刻重試,多半還是會失敗。建議設置為「1」。
- Sleep :如果沒有有效的任務,那么系統暫停幾秒后再重新檢查。此時間的缺省值為「3」。不過如此一來的話,那么如果突然來了一個新任務,那么就可能暫停3秒后才能開始響應,很多時候這顯得有點太長了。建議設置為「1」。
- Tries :如果一個任務失敗了,那么重試幾次。此次數的缺省值為「0」,不過它的含義可不是不重試,而是不斷重試。某些時候,如果問題比較嚴重,不斷重試就等同于死循環。建議設置為「3」。
在生產環境中,很容易忽視的一點是監控隊列是否發生了擁堵,以 beanstalk 為例,它提供了 stats 命令,讓我們能夠很方便的查詢隊列狀態:
shell> echo -e "stats\r" | nc <IP> <PORT>
不過這個命令有很多輸出,我們如何判斷哪些和擁堵相關呢?最簡單的方法是人為的制造一些擁堵的故障,然后對比前后的結果找差異,我試驗的結果是如下幾項:
- current-jobs-urgent
- current-jobs-ready
- current-jobs-reserved
- current-jobs-delayed
- current-jobs-buried
我們可以通過 zabbix 很方便的監控 beanstalk 是否發生了擁堵:

Beanstalk Jobs
具體的配置方法我就不贅述了,大家可以參考官網中對于 UserParameters 的描述。