webman明明還有空閑子進(jìn)程,為什么接收到新請(qǐng)求時(shí)卻分配不到空閑進(jìn)程?
進(jìn)程(webman子進(jìn)程)
客戶端(發(fā)起請(qǐng)求的IP+發(fā)起請(qǐng)求時(shí)所使用的端口號(hào))
經(jīng)過(guò)測(cè)試發(fā)現(xiàn)一個(gè)現(xiàn)象,webman在處理請(qǐng)求時(shí),似乎會(huì)把該進(jìn)程和客戶端做一個(gè)綁定關(guān)系,該客戶端下次發(fā)起請(qǐng)求時(shí),webman會(huì)用該客戶端上一次使用過(guò)的子進(jìn)程進(jìn)行處理;
這樣就會(huì)出現(xiàn)一個(gè)問(wèn)題,可能這一個(gè)子進(jìn)程綁定了多個(gè)客戶端,假設(shè)該子進(jìn)程在處理某一次請(qǐng)求時(shí)耗時(shí)30秒鐘,在此期間與該子進(jìn)程綁定的客戶端發(fā)起新的請(qǐng)求就都會(huì)阻塞住(直到30秒鐘后才能響應(yīng)請(qǐng)求,因?yàn)榇藭r(shí)子進(jìn)程處于阻塞狀態(tài)),但是此時(shí)還有很多其它的空閑子進(jìn)程,要怎樣才能把請(qǐng)求分配給空閑子進(jìn)程處理呢?(就像php-fpm那樣,一個(gè)子進(jìn)程只處理一個(gè)請(qǐng)求,請(qǐng)求結(jié)束后進(jìn)程銷毀,這樣就不會(huì)因?yàn)橐粋€(gè)請(qǐng)求影響到另外一個(gè)請(qǐng)求)
同時(shí)發(fā)起10個(gè)請(qǐng)求,其中端口42610發(fā)起的請(qǐng)求被分配到了子進(jìn)程12086上面(12806進(jìn)程此時(shí)還在處理42612端口的請(qǐng)求)所以此時(shí)42610只能等待12806進(jìn)程處理完42612的請(qǐng)求,30秒后,42610發(fā)起的請(qǐng)求得到響應(yīng)
請(qǐng)求頭
響應(yīng)頭
Nginx代理配置
location ~* /v2 {
proxy_buffering on;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_buffer_size 256k;
proxy_buffers 64 128k;
proxy_busy_buffers_size 512k;
proxy_temp_file_write_size 256k;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_read_timeout 600;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_pass http://172.19.0.2:8787;
#proxy_pass http://webman1;
rewrite "^/v2/(.*)$" /$1;
break;
}
測(cè)試模擬業(yè)務(wù)耗時(shí)20秒,開啟10個(gè)進(jìn)程并發(fā)請(qǐng)求,一共發(fā)起2輪請(qǐng)求
//模擬業(yè)務(wù)耗時(shí)場(chǎng)景
public function test(Request $request)
{
Log::info(['runTest' => posix_getpid(), 'port' => $request->getRemotePort(), 'time' => time()]);
Db::select('select sleep(20);');
return json(['data' => date('Y-m-d H:i:s')]);
}
1、自定義進(jìn)程中添加一個(gè)處理請(qǐng)求進(jìn)程(config/process.php)
<?php
return [
'server' => [
'handler' => \app\Server::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 500, // 啟動(dòng)進(jìn)程數(shù)
'constructor' => [
'request_class' => \support\Request::class, // request類設(shè)置
'logger' => \support\Log::channel('default'), // 日志實(shí)例
'app_path' => app_path(), // app目錄位置
'public_path' => public_path() // public目錄位置
]
]
];
2、處理請(qǐng)求類源碼(app/server.php)
<?php
namespace app;
use Webman\App;
use Workerman\Connection\TcpConnection;
class Server extends App
{
public function onConnect(TcpConnection $connection)
{
$connection->worker->pauseAccept();
}
public function onMessage($connection, $request)
{
parent::onMessage($connection, $request);
$connection->worker->resumeAccept();
}
public function onClose($connection)
{
$connection->worker->resumeAccept();
}
}
3、把原來(lái)執(zhí)行8787端口的請(qǐng)求指向8686
經(jīng)過(guò)測(cè)試,已經(jīng)達(dá)到目的,最大并發(fā)量等于啟動(dòng)的server進(jìn)程數(shù),并發(fā)高的時(shí)候增加config/process.php 里server進(jìn)程的count啟動(dòng)進(jìn)程數(shù)量就行
客戶端連接到某個(gè)進(jìn)程后,這個(gè)連接上發(fā)的數(shù)據(jù)都會(huì)發(fā)給這個(gè)進(jìn)程。
如果你不需要這種機(jī)制,可以在webman前面放一個(gè)nginx代理,nginx代理不開啟keep-alive?;蛘呖蛻舳苏?qǐng)求時(shí)加一個(gè)header Connection: close
也可以
關(guān)于 請(qǐng)求集中在某些進(jìn)程 參考手冊(cè)
http://wtbis.cn/doc/workerman/faq/requests-concentrated-in-certain-processes.html
感謝大佬的答惑,經(jīng)過(guò)測(cè)試,好像還是沒(méi)有用,不知道是不是我哪一步弄錯(cuò)了,麻煩幫忙再看看,相關(guān)貼圖在上方
目前的確是使用的Nginx代理做了一次轉(zhuǎn)發(fā)的,但是可能我哪一步做的不對(duì),上方貼圖Nginx代理配置塊,麻煩幫忙看看是否有錯(cuò)誤
手冊(cè)這個(gè)配置 http://wtbis.cn/doc/webman/others/nginx-proxy.html
keepalive 10240; 去掉
經(jīng)過(guò)測(cè)試,發(fā)現(xiàn)還是沒(méi)有效果,此次測(cè)試模擬了業(yè)務(wù)耗時(shí)20秒,開了10個(gè)進(jìn)程并發(fā)請(qǐng)求,一共請(qǐng)求2輪,結(jié)果還是跟最初的一樣,貼圖上方,麻煩幫忙再看看
大佬你好,我之前就已經(jīng)把reusePort設(shè)置為true了,但是經(jīng)過(guò)測(cè)試還是不能達(dá)到我想要的效果
reusePort現(xiàn)在已經(jīng)設(shè)置為true了,Nginx也關(guān)閉keepalive了(按你前面說(shuō)的把keepalive 10240;這行配置刪除了)webman和Nginx都重啟過(guò),難道是因?yàn)槲疫€有別的Nginx配置項(xiàng)會(huì)影響到嗎?不知道大佬方不方便微信聯(lián)系,希望能提供下付費(fèi)支持,解決我這個(gè)問(wèn)題。
workerman里是開啟端口復(fù)用 reusePort=true,webman應(yīng)該也有類似配置,我們之前也遇到過(guò)這個(gè)問(wèn)題。
webman里config/server.php里可以設(shè)置reusePort。
不過(guò)reusePort 是讓連接平均分配給所有進(jìn)程,不是題主要的效果。
題主的問(wèn)題不像是長(zhǎng)連接導(dǎo)致倒是像未開啟reusePort,我們起初也錯(cuò)誤的使用$conn->send來(lái)發(fā)送導(dǎo)致全是長(zhǎng)連接,但開啟了多進(jìn)程端口復(fù)用,也能扛得住的啊 哈哈
題主要的效果是A進(jìn)程在處理慢業(yè)務(wù),那么就不分配請(qǐng)求給A進(jìn)程。
如果是開長(zhǎng)連接+reusePort,每個(gè)進(jìn)程都會(huì)有多個(gè)連接,A進(jìn)程在處理慢業(yè)務(wù),那么這個(gè)時(shí)候A進(jìn)程的它連接可能會(huì)發(fā)來(lái)請(qǐng)求,這些請(qǐng)求都會(huì)等待慢業(yè)務(wù)處理完畢才能得到處理。
是的,需要達(dá)到的目的就是只要還有空閑進(jìn)程,那新進(jìn)來(lái)的請(qǐng)求就一定能夠得到處理,而不是分配到一個(gè)繁忙的進(jìn)程上等待處理,目前我們項(xiàng)目已經(jīng)上線運(yùn)行大半年了,但是最近流量大起來(lái),發(fā)現(xiàn)扛不住大并發(fā)的場(chǎng)景,現(xiàn)在很著急如何解決這樣的問(wèn)題
有標(biāo)準(zhǔn)解決方案嗎?這個(gè)問(wèn)題很經(jīng)典,也很普遍,項(xiàng)目中可能遇到就是致命的問(wèn)題,希望能共享解決方案