日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

laravel 任务队列_laravel队列-让守护进程处理耗时任务

發布時間:2025/3/12 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 laravel 任务队列_laravel队列-让守护进程处理耗时任务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

待解決的問題

最近在做一個服務器集群管理的web項目,需要處理一些極其耗時的操作,比如磁盤格式化分區。對于這個需求,最開始的想法是,為了讓節點上的rpc(遠程過程調用)?service端盡可能簡單(簡單到只需要popen執行一條指令即可,有時間我再專門寫一篇博客講講這個項目的rpc是如何實現的),我們選擇了讓web端直接等待處理結果,那么問題來了,如何保證用戶不必等待,又能保證任務準確的執行呢?

簡單的rpc結構如下圖

以往在處理一些稍微耗時的操作,可以通過優化代碼結構,優化數據庫操作次數,起一些線程來處理一些簡單的比如發郵件,生成大的壓縮文件,提取視頻縮量圖,服務器間互訪等等操作,來避免用戶在web頁面的等待。

但現在這個操作顯然不能用之前的這些方法做,因為現在的操作哪怕只執行一次,都是非常耗時的,更何況可能需要處理的可能是上百上千臺服務器。這是在線程層面很難做,要知道在響應請求的web進程中起一個線程來做的話,在響應完斷開tcp連接之后,這個進程很可能被kill掉,像Apache就是這樣,當然可以通過配置改變apache的行為,但顯然不太靠譜。

更好的做法是在web服務器上起一個守護進程去做這個事情,那么問題就在于如何創建守護進程了,好在laravel幫我們考慮了這個事情。

Laravel的隊列

laravel的隊列默認是以sync(同步)的方式來處理多個任務,這顯然不是我們想要的。鑒于這個項目使用的是laravel4.1版本,我選擇了beanstalkd來實現異步處理多個任務。

其中beanstalkd是一種比較專業的隊列服務驅動器,是一個常駐后臺服務,我們可以通過它提供的接口來把任務提交給它,由它創建的守護進程來執行隊列。

配置隊列執行環境

1.安裝beanstalkd服務

我開發的電腦為CentOS5.4,版本比較低,所以裝的過程中還是遇到些麻煩

首先執行下面的指令

1 wget ftp://fr2.rpmfind.net/linux/epel/5/ppc/epel-release-5-4.noarch.rpm

2 rpm -ivh epel-release-5-4.noarch.rpm3 yummakecache4 yum search beanstalkd

但最后發現找不到這個軟件,于是將yum的源換成了163的

1 cd /etc/yum.repos.d2 wget http://mirrors.163.com/.help/CentOS5-Base-163.repo

3 mv CentOS-Base.repo CentOS-Base.repo.bak

再次makecache && install 就OK了,安裝完后啟動beanstalkd服務

1 service beanstalkd start

另外可以搜索到beanstalkd的配置文件放在了sysconfig下

為laravel添加beanstalkd的驅動

beanstalkd的php驅動包為pda/pheanstalk

進入laravel的protected目錄,composer.json在這個目錄下

執行

1 composer require pda/pheanstalk 2.*

出現如下的錯誤

可以看出鏡像地址響應 502,所以需要給composer找一個可用的鏡像?http://www.phpcomposer.com/

修改~/.composer/config.json如下

然后回到protected目錄,再執行前面安裝驅動的命令安裝,這回出現了不一樣的錯誤

上面的php包中,第一個是為了phpstorm的對laravel更好的支持,后面一個symfony/yaml已經安裝,并不需要升級,所以修改composer.json,直接將這兩個項目刪除掉就行了

刪除完之后,再次執行安裝命令安裝

可以看到終于成功了,可以通過 composer show -i 查看安裝了哪些包

測試

在TestController中添加一個action

1 class TestController extendsBaseController2 {3

4 public functiongetQueue(){5 //6 Log::info("添加一個對列任務");7 Queue::push('SendEmail',array('message'=>'哈哈'));8 Log::info('任務添加完畢');9 exit;10 }11

12 }

在app目錄下新建tasks目錄,并修改protected/composer.json和app/global.php,將這個目錄加到類加載路徑中

修改global.php

1 ClassLoader::addDirectories(array(2

3 app_path().'/commands',

4 app_path().'/controllers',

5 app_path().'/models',

6 app_path().'/database/seeds',

7 app_path().'/library',

8 app_path().'/tasks',

9 ));

修改composer.json

1 "classmap": [2 "app/commands",3 "app/controllers",4 "app/models",5 "app/database/migrations",6 "app/database/seeds",7 "app/tasks",8 "app/tests/TestCase.php"

9 ]

以后的耗時調度任務的代碼就放在這個目錄下面了

首先新建一個BaseTask.php

1 /**2 * Created by PhpStorm.3 * User: Administrator4 * Date: 2015/8/19 00195 * Time: 11:556 */

7 abstract classBaseTask8 {9 public abstract function fire($job,$data);10 }

然后新建一個SendMail.php

1 /**2 * Created by PhpStorm.3 * User: Administrator4 * Date: 2015/8/19 00195 * Time: 11:506 */

7 class SendEmail extendsBaseTask8 {9

10 public function fire($job, $data)11 {12 //TODO: Implement fire() method.

13 Log::info("對列任務執行".json_encode($data)."Time : ".time());14 sleep(30);15 Log::info("對列任務執行完畢".time());16 //將任務從隊列沖刪除

17 $job->delete();18 //將任務返回到隊列19

20 // $job->release();

21

22 }23 }

最后就是去修改config目錄下的配置文件queue.php文件了,修改為

1 'default' => 'beanstalkd',

1 'beanstalkd' => array(2 'driver' => 'beanstalkd',

3 'host' => 'localhost',

4 'queue' => 'default',

5 'ttr' => 60,

6 ),

關于ttr的解釋這里有一個

表示time to run ,這個參數可以覆蓋默認參數讓Beanstalkd?檢測是否在這個時間內完成

至此配置和寫代碼完成,在shell中執行,要在protected目錄下,artisan文件在這個目錄下

1 php artisan queue:work2 php artisan queue:listen

查看protected/app/storage/logs/laravel.log 可以看到下面的內容

508-478 剛好30秒

下面測試一個實際的問題,印象中apache服務器與客戶端在請求完成斷開連接后會kill掉負責處理的httpd進程,只有配置了keep-alive參數在會將進程保留到apache進程池中,所以,但用戶請求一個耗時操作之后,關閉了瀏覽器,這個處理耗時任務的守護進程會不會也被kill掉呢?當然,其實有點多慮了,當響應完成之后tcp鏈接已經被斷開掉了,如果進程會被kill掉,那么早就kill掉了,跟你瀏覽器關沒關應該沒多大關系,還是試試吧,實踐才是硬道理

這里將SendMial中的sleep時間改長一點,改為 600秒

最后發現沒有執行完,可以看到listen報出異常

很顯然執行超時,看來是前面設置的ttr的問題

將ttr注釋掉或者修改掉更高的值,發現還是不行,最后在仔細看看報錯信息,發現

所以改變命令的執行方式

1 php artisan queue:listen --timeout=800

最后命令任務成功執行完畢

可以看到 1353-753 = 600 剛剛好

另外,看樣子 這個任務對列應該是被保存起來了,當我沒有啟動 listen時,任務怎么都不會處理,但我一但啟動listen,前面添加的任務就會立馬執行

但最后還是有個問題這個是對列形式進行處理,要啟動下一個對列任務,必須等上一個對列任務執行完畢,不過之前曾看到過,一個work對應一個任務隊列,那么我完全可以起多個任務隊列,有點多核CPU的調度哦。

更好的辦法

最后,再跟一位大神討論了一下,探討出了另外一個更加優秀的辦法,雖然會加重節點上rpc service代碼的復雜度,不過也不是很麻煩。

這種方式就是回調,管理集群的web服務器可以不用等待,只需如下步驟,

通過web服務器上的rpc client向要執行耗時操作的節點上的rpc service發送一條指令,

節點上的rpc service收到指令后,不先執行指令,而是馬上向web服務器,也就是rpc client返回一個任務ID。

web服務器將這個id作為一條任務記錄保存到數據庫。

節點上的rpc service處理指令,至于處理指令,也是在節點上在單獨起一個進程 P 來處理,因為rpc service也不能讓rpc client傻等著

處理進程 P 處理完了之后,將執行結果和任務ID作為參數,回調web服務器的一個web接口

web服務器接到rpc service的回調之后,通過ID查找到任務,更新任務的執行狀態,更新數據

很顯然,這種方式更加可靠,也大大減輕了web 服務器的負擔,要知道Linux 系統的線程數是有限制的,但這要耗時任務多了,如果然服務器去等,不管啥策略都很可能吧服務器整垮。

總結

以上是生活随笔為你收集整理的laravel 任务队列_laravel队列-让守护进程处理耗时任务的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。