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