webman是不是不適合做依賴第三方接口的實時應(yīng)用,比如某服務(wù),需要依賴第三方的接口去查詢用戶信息,如果第三方接口的響應(yīng)時間需要5秒(假設(shè)),同時進(jìn)來50個請求(開啟4個進(jìn)程監(jiān)聽的話),那么是不是就會導(dǎo)致另外的46個請求至少要等5秒之后才有響應(yīng)呢?如果想用webman實現(xiàn)這個業(yè)務(wù)類型應(yīng)用是否有解決方案?
fpm模式的進(jìn)程一樣是阻塞的,它應(yīng)對的方法無法就是多開進(jìn)程,相對應(yīng)的,webman也可以多開,對于這種阻塞嚴(yán)重的,你搞個一兩百進(jìn)程都可以.
這種場景適合用workerman來做,配合workerman/http-client
這樣也不行,只能多開進(jìn)程,workerman/http-client是異步請求,無法和安卓ios等前端響應(yīng)。樓主提的這個問題確實是php的短板,php一般基于進(jìn)程而不是線程,如果是基于線程的話就很好解決樓主的問題,比如go的協(xié)程。
@evilk 協(xié)程可以開很多,因為開銷很小,當(dāng)前協(xié)程可以等待三方接口響應(yīng)后再返回給前端,不像php一樣受進(jìn)程數(shù)量限制,協(xié)成它確實不會縮短三方接口的請求時間,但是可以同時處理更多前端請求,一個前端請求對應(yīng)一個協(xié)程
在等待異步回調(diào)時難道要休眠掛起當(dāng)前客戶端連接嗎?不然等回調(diào)時客戶端連接已經(jīng)斷開了沒法再返回數(shù)據(jù)了。
其他語言也會有線程/進(jìn)程數(shù)量的限制吧。go的http的是來一個請求創(chuàng)建一個協(xié)程。你這種場景是高io,低運算的場景,可以和其他接口分開單獨開一個服務(wù)器,然后把webman的數(shù)量調(diào)整高一點,畢竟你的這個場景大多是在等待,把運算型和io型的分開也可以
這種場景適合直接workerman + workerman/http-client 來做,純異步的,沒有所謂的協(xié)程消耗,代碼類似這樣
require_once __DIR__ . '/vendor/autoload.php';
use Workerman\Connection\TcpConnection;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;
$worker = new Worker('http://0.0.0.0:1234');
$worker->onMessage = function (TcpConnection $connection, Request $request) {
$http = new Workerman\Http\Client();
$http->get('https://example.com/', function ($response) use ($connection) {
$connection->send((string)$response->getBody());
}, function ($exception) use ($connection) {
$connection->send((string)$exception);
});
};
Worker::runAll();
你說的這種業(yè)務(wù)場景不論是哪種語言,都一樣,瓶頸不在webman,也不在語言。
假設(shè)你的服務(wù)叫A,你需要調(diào)用B服務(wù)的相關(guān)API實現(xiàn)同步阻塞的工作流,這沒問題,但現(xiàn)在你說這個過程可能很長,需要5秒,QPS可能達(dá)到幾千,這沒問題;
從每一個請求到每一個請求完畢假設(shè)就是5秒,實際上你的服務(wù)器需要承受這5秒內(nèi)累計的請求數(shù)量,只要能承受就沒問題;
這取決于是否使用http長連接,服務(wù)器是否有這樣的承載能力,畢竟每臺服務(wù)器的socket連接是由上限的,太多了可能會出現(xiàn)close wait,或是緩沖區(qū)沾滿,或是內(nèi)存超限等情況;
在使用了http長連接的前提下,并且你的服務(wù)器內(nèi)核做了調(diào)優(yōu),對于socket連接有做優(yōu)化,workerman的緩沖區(qū)設(shè)置大一些,php的內(nèi)存限制調(diào)大一些,這些前提下,是沒問題的;只要在你累計請求的過程中保證承載量可以達(dá)到就OK,剩下的就交給webman的reactor模型就好了;
這里有必要說一下,其他語言也同樣這樣處理,不論是開線程也好還是開進(jìn)程也好,都是提高短時間的承載量,但都受限于消費的速度和服務(wù)器自身的承載量,如果使用線程/進(jìn)程,CPU的決定了調(diào)度效率;內(nèi)存/磁盤決定了資源承載量極限;
workerman/webman的reactor模型實際上利用了系統(tǒng)的事件循環(huán),本質(zhì)上和多線程/多進(jìn)程沒差,外加上workerman/webman是使用了multi-reactor(也就是多進(jìn)程的),利用多核,處理能力也翻番,絲毫不需要擔(dān)心。
其實說了那么多,說白了,最后就是一個吞量載量問題,和語言真的沒什么關(guān)系。
另外,協(xié)程如果僅僅用協(xié)程,是沒辦法并發(fā)的,協(xié)程現(xiàn)在的玩法有這幾種:
協(xié)程本質(zhì)上解決的是event-loop這種異步回調(diào)模式會帶來很多編寫代碼和理解代碼的不便,從異步開發(fā)的發(fā)展歷史就可以得出這個結(jié)論:
回調(diào)地獄 -> promises -> aysnc/wait -> 協(xié)程
協(xié)程開多了不處理,還是會累積在線程上,線程池的數(shù)量又有上線,最后還是回到了載量問題上。
目前建議workerman或者webman自定義進(jìn)程去做。
后面workerman v5+fiber可以讓webman做到利用http-client寫同步代碼發(fā)起異步非阻塞請求,參考 http://www.wtbis.cn/q/8696#answer_13638
起一個非阻塞服務(wù)吧,比如swoole或者其他非阻塞的httpclient包,也可結(jié)合隊列,多進(jìn)程方式處理。
不考慮 依賴的第三方接口服務(wù)的性能的情況下,本身能做的:非阻塞+多進(jìn)程處理