慢業(yè)務處理
有時候我們需要處理慢業(yè)務,為了避免慢業(yè)務影響webman的其它請求處理,這些業(yè)務根據(jù)情況不同可以使用不同的處理方案。
方案一 使用消息隊列
優(yōu)點
可以應對突發(fā)海量業(yè)務處理請求
缺點
無法直接返回結果給客戶端。如需推送結果需要配合其它服務,例如使用 webman/push 推送處理結果。
方案二 新增HTTP端口
新增HTTP端口處理慢請求,這些慢請求通過訪問這個端口進入特定的一組進程處理,處理后將結果直接返回給客戶端。
優(yōu)點
可以直接將數(shù)據(jù)返回給客戶端
缺點
無法應對突發(fā)的海量請求
實施步驟
在 config/process.php
里增加如下配置。
return [
// ... 這里省略了其它配置 ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // 進程數(shù)
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // request類設置
'logger' => \support\Log::channel('default'), // 日志實例
'appPath' => app_path(), // app目錄位置
'publicPath' => public_path() // public目錄位置
]
]
];
這樣慢接口可以走 http://127.0.0.1:8686/
這組進程,不影響其它進程的業(yè)務處理。
為了讓前端無感知端口的區(qū)別,可以在nginx加一個到8686端口的代理。假設慢接口請求路徑都是以/tast
開頭,整個nginx配置類似如下:
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# 新增一個8686 upstream
upstream task {
server 127.0.0.1:8686;
keepalive 10240;
}
server {
server_name webman.com;
listen 80;
access_log off;
root /path/webman/public;
# 以/tast開頭的請求走8686端口,請按實際情況將/tast更改為你需要的前綴
location /tast {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://task;
}
# 其它請求走原8787端口
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Connection "";
if (!-f $request_filename){
proxy_pass http://webman;
}
}
}
這樣客戶端訪問域名.com/tast/xxx
時將會走單獨的8686端口處理,不影響8787端口的請求處理。
方案三 利用http chunked 異步分段發(fā)送數(shù)據(jù)
優(yōu)點
可以直接將數(shù)據(jù)返回給客戶端
安裝 workerman/http-client
composer require workerman/http-client
app/controller/IndexController.php
<?php
namespace app\controller;
use support\Request;
use support\Response;
use Workerman\Protocols\Http\Chunk;
class IndexController
{
public function index(Request $request)
{
$connection = $request->connection;
$http = new \Workerman\Http\Client();
$http->get('https://example.com/', function ($response) use ($connection) {
$connection->send(new Chunk($response->getBody()));
$connection->send(new Chunk('')); // 發(fā)送空的的chunk代表response結束
});
// 先發(fā)送一個http頭,后續(xù)數(shù)據(jù)通過異步發(fā)送
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
提示
本例中使用了workerman/http-client
客戶端異步獲取http結果并返回數(shù)據(jù),也可以使用其它異步客戶端例如 AsyncTcpConnection 。