webman明明還有空閑子進程,為什么接收到新請求時卻分配不到空閑進程?
進程(webman子進程)
客戶端(發(fā)起請求的IP+發(fā)起請求時所使用的端口號)
經(jīng)過測試發(fā)現(xiàn)一個現(xiàn)象,webman在處理請求時,似乎會把該進程和客戶端做一個綁定關(guān)系,該客戶端下次發(fā)起請求時,webman會用該客戶端上一次使用過的子進程進行處理;
這樣就會出現(xiàn)一個問題,可能這一個子進程綁定了多個客戶端,假設(shè)該子進程在處理某一次請求時耗時30秒鐘,在此期間與該子進程綁定的客戶端發(fā)起新的請求就都會阻塞?。ㄖ钡?0秒鐘后才能響應(yīng)請求,因為此時子進程處于阻塞狀態(tài)),但是此時還有很多其它的空閑子進程,要怎樣才能把請求分配給空閑子進程處理呢?(就像php-fpm那樣,一個子進程只處理一個請求,請求結(jié)束后進程銷毀,這樣就不會因為一個請求影響到另外一個請求)
同時發(fā)起10個請求,其中端口42610發(fā)起的請求被分配到了子進程12086上面(12806進程此時還在處理42612端口的請求)所以此時42610只能等待12806進程處理完42612的請求,30秒后,42610發(fā)起的請求得到響應(yī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;
}
測試模擬業(yè)務(wù)耗時20秒,開啟10個進程并發(fā)請求,一共發(fā)起2輪請求
//模擬業(yè)務(wù)耗時場景
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、自定義進程中添加一個處理請求進程(config/process.php)
<?php
return [
'server' => [
'handler' => \app\Server::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 500, // 啟動進程數(shù)
'constructor' => [
'request_class' => \support\Request::class, // request類設(shè)置
'logger' => \support\Log::channel('default'), // 日志實例
'app_path' => app_path(), // app目錄位置
'public_path' => public_path() // public目錄位置
]
]
];
2、處理請求類源碼(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、把原來執(zhí)行8787端口的請求指向8686
經(jīng)過測試,已經(jīng)達到目的,最大并發(fā)量等于啟動的server進程數(shù),并發(fā)高的時候增加config/process.php 里server進程的count啟動進程數(shù)量就行
客戶端連接到某個進程后,這個連接上發(fā)的數(shù)據(jù)都會發(fā)給這個進程。
如果你不需要這種機制,可以在webman前面放一個nginx代理,nginx代理不開啟keep-alive。或者客戶端請求時加一個header Connection: close
也可以
關(guān)于 請求集中在某些進程 參考手冊
http://wtbis.cn/doc/workerman/faq/requests-concentrated-in-certain-processes.html
目前的確是使用的Nginx代理做了一次轉(zhuǎn)發(fā)的,但是可能我哪一步做的不對,上方貼圖Nginx代理配置塊,麻煩幫忙看看是否有錯誤
經(jīng)過測試,發(fā)現(xiàn)還是沒有效果,此次測試模擬了業(yè)務(wù)耗時20秒,開了10個進程并發(fā)請求,一共請求2輪,結(jié)果還是跟最初的一樣,貼圖上方,麻煩幫忙再看看
reusePort現(xiàn)在已經(jīng)設(shè)置為true了,Nginx也關(guān)閉keepalive了(按你前面說的把keepalive 10240;這行配置刪除了)webman和Nginx都重啟過,難道是因為我還有別的Nginx配置項會影響到嗎?不知道大佬方不方便微信聯(lián)系,希望能提供下付費支持,解決我這個問題。
workerman里是開啟端口復(fù)用 reusePort=true,webman應(yīng)該也有類似配置,我們之前也遇到過這個問題。
題主的問題不像是長連接導(dǎo)致倒是像未開啟reusePort,我們起初也錯誤的使用$conn->send來發(fā)送導(dǎo)致全是長連接,但開啟了多進程端口復(fù)用,也能扛得住的啊 哈哈
題主要的效果是A進程在處理慢業(yè)務(wù),那么就不分配請求給A進程。
如果是開長連接+reusePort,每個進程都會有多個連接,A進程在處理慢業(yè)務(wù),那么這個時候A進程的它連接可能會發(fā)來請求,這些請求都會等待慢業(yè)務(wù)處理完畢才能得到處理。
是的,需要達到的目的就是只要還有空閑進程,那新進來的請求就一定能夠得到處理,而不是分配到一個繁忙的進程上等待處理,目前我們項目已經(jīng)上線運行大半年了,但是最近流量大起來,發(fā)現(xiàn)扛不住大并發(fā)的場景,現(xiàn)在很著急如何解決這樣的問題