swPromisePHP純異步非阻塞框架
swPromise,基于swoole的PHP promise框架
一個(gè)業(yè)務(wù)請求可能會串行的請求多個(gè)接口A-> B-> C,此時(shí)如果接口B的響應(yīng)時(shí)間較慢(關(guān)鍵性業(yè)務(wù),需要有預(yù)先準(zhǔn)備好的超時(shí)等待時(shí)間),并導(dǎo)致請求整體的時(shí)間過長,嚴(yán)重降低系統(tǒng)的響應(yīng)能力??紤]到這個(gè)業(yè)務(wù)場景下,進(jìn)展的主要時(shí)間用在等待網(wǎng)絡(luò)io返回。的方式,逐漸極大的提升服務(wù)的爆炸(NodeJS的優(yōu)勢)。
如果某接口響應(yīng)時(shí)間超過往常,會導(dǎo)致php-fpm過程數(shù)急劇上升,從而導(dǎo)致大量cpu資源浪費(fèi)在進(jìn)程調(diào)度上面,甚至導(dǎo)致服務(wù)崩潰。swPromise框架是為了解決該問題而開發(fā)的。
傳統(tǒng)上,為進(jìn)行初始化調(diào)用,會在代碼中實(shí)現(xiàn)大量的替換函數(shù),導(dǎo)致代碼發(fā)生性與可維護(hù)性的急劇下降。為了解決這個(gè)問題,主流方案有以下幾種:
-
自定義事件式方案
-
承諾/推遲
-
高階函數(shù)修正改局部函數(shù)
-
協(xié)程(發(fā)電機(jī))
Swoole是PHP語言的高級網(wǎng)絡(luò)通信框架,提供了PHP語言的異步多線程服務(wù)器。swoole采用自定義事件樣式方案,為我們提供網(wǎng)絡(luò)層基本封裝?;趕woole,可以擴(kuò)展出業(yè)務(wù)層的模擬開發(fā)框架。
tsf(騰訊服務(wù)器框架)是騰訊公司推出的PHP協(xié)程方案,基于Swoole + PHP Generator實(shí)現(xiàn)的協(xié)程。該框架使用協(xié)程模式,基于swoole與swoole框架開發(fā)。實(shí)現(xiàn)了真正的異步非多重開發(fā)模式,同時(shí)具有極高的性能。其核心代碼來源于該文章協(xié)同多任務(wù)處理使用協(xié)同程序(在PHP中?。?/a>。TSF使用了較為復(fù)雜的用戶態(tài)任務(wù)調(diào)度邏輯,在騰訊的OpenAPI中使用。另外由于使用了swoole框架,略顯重量級。
該類實(shí)現(xiàn)了基本的然后的方法,并通過對Promise流程的延遲計(jì)算,保證了流程的動(dòng)態(tài)控制能力。該框架是一個(gè)非?;A(chǔ)的Web框架。 ,目前僅實(shí)現(xiàn)通用Future(通用延遲計(jì)算),HttpClientFuture,ResponseFuture三個(gè)連續(xù)計(jì)算類。
該框架需要配合Swoole master版本使用,編譯參數(shù)。/configure--enable-async-httpclient,開啟初始化http client。
演示代碼
class Handler_Index extends \Core\Handler{
public function run($request, $response){
Promise::create ( Model::getUserInfo ( 'user1', 'haha' ) )
->then (function(&$promise){
$user1 = $promise->get('user1');
if($user1){
return Model::getUserInfo ( 'user2', 'haha2' )
->then(function(&$promise){
$user2 = $promise->get('user2');
$promise->accept(['user3'=>$user2['body']]);
});
}
else $promise->accept();
})
->then ( Model::getUserInfo ( 'user4', 'haha4' ) )
->then ( Model::getUserInfo ( 'user5', 'haha5' ) )
->then ( new ResponseFuture ($response) )
->start ( new PromiseContext () );
}
}
這段流程表明了,先獲取haha這個(gè)用戶的信息,寫入上下文的user1字段中。 如果獲取到了數(shù)據(jù),再獲取haha2這個(gè)用戶的信息,寫入上下文user2字段中。 并將user2的body字段放入user3字段中。然后獲取haha4和haha5的信息。 最后將所有數(shù)據(jù)輸出到網(wǎng)頁。
可以看到,在第一個(gè)then中,通過if條件返回promise對象,實(shí)現(xiàn)了對異步流程的動(dòng)態(tài)控制。 同樣的,整個(gè)流程通過then串聯(lián)起來,已經(jīng)較為接近同步代碼的書寫了。 而使用回調(diào)的方式,代碼會變得極為恐怖。
并行請求
class Handler_Index extends \Core\Handler{
public function run($request, $response){
Promise::create([
Model::getUserInfo ( 'user1', 'haha' ),
Model::getUserInfo ( 'user2', 'haha2' ),
])->then(
new ResponseFuture ($response)
)->start(new PromiseContext ());
}
}
這個(gè)請求并行獲得haha與hah2兩個(gè)用戶的數(shù)據(jù),分布放到user1和user2兩個(gè)字段中。
存在問題
其中Handler_Sync實(shí)現(xiàn)的就是該框架同步的使用方式。 另外,目前reject方法以及異常處理流程均沒有實(shí)現(xiàn),有興趣的朋友可以自行擴(kuò)展。
目前有一個(gè)比較嚴(yán)重的bug,如果大量http request沒有完成就自行中斷的話,會導(dǎo)致swoole http server發(fā)生錯(cuò)誤,從而退出。在swoole前面放一個(gè)nginx就可以解決問題。
測試方法
啟動(dòng)
php run.php
測試:
ab -n 10000 -c 100 "http://localhost:9502/async" ab -n 10000 -c 100 "http://localhost:9502/sync"
經(jīng)過測試,在后端接口響應(yīng)性能有問題的情況下,swPromise 可以同時(shí)處理大量連接,用很低的 cpu 負(fù)載等待接口數(shù)據(jù)返回。
