Elaborazione di richieste lente
A volte è necessario gestire richieste lente. Per evitare che le richieste lente influenzino l'elaborazione delle altre richieste da parte di Webman, è possibile adottare diverse soluzioni a seconda della situazione.
Soluzione 1 Utilizzo di una coda dei messaggi
Fare riferimento a coda redis coda stomp
Vantaggi
Può gestire picchi imprevisti di richieste di elaborazione.
Svantaggi
Non è possibile restituire direttamente i risultati al client. Se è necessario inviare i risultati, è necessario utilizzare altri servizi, come ad esempio la funzionalità di push di webman/push.
Soluzione 2 Aggiunta di una porta HTTP
Aggiungere una porta HTTP per gestire le richieste lente. Queste richieste lente entreranno in un gruppo specifico di processi attraverso questa porta e i risultati verranno restituiti direttamente al client.
Vantaggi
Può restituire direttamente i dati al client.
Svantaggi
Non può gestire picchi imprevisti di richieste.
Passaggi di implementazione
Aggiungere la seguente configurazione in config/process.php
.
return [
// ... altre configurazioni omesse ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // numero di processi
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // impostazione della classe request
'logger' => \support\Log::channel('default'), // istanza di log
'appPath' => app_path(), // posizione della directory app
'publicPath' => public_path() // posizione della directory public
]
]
];
In questo modo, l'interfaccia lenta può passare attraverso http://127.0.0.1:8686/
, senza influenzare l'elaborazione delle altre richieste.
Per consentire al front-end di non percepire la differenza tra le porte, è possibile aggiungere un proxy a nginx per la porta 8686. Supponendo che i percorsi delle richieste delle interfacce lente inizino tutti con /tast
, la configurazione di nginx sarà simile a questa:
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# Aggiungere un nuovo upstream per 8686
upstream task {
server 127.0.0.1:8686;
keepalive 10240;
}
server {
server_name webman.com;
listen 80;
access_log off;
root /path/webman/public;
# Le richieste che iniziano con /tast passano attraverso la porta 8686, si prega di modificare /tast in base alle esigenze
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;
}
# Altre richieste passano attraverso la porta originale 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;
}
}
}
In questo modo, quando il client accede a dominio.com/tast/xxx
, verrà gestito dalla porta 8686, senza influenzare l'elaborazione delle richieste sulla porta 8787.
Soluzione 3 Utilizzare l'invio dei dati in chunk HTTP asincrono
Vantaggi
Può restituire direttamente i dati al client.
Installare 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('')); // invia un chunk vuoto per segnalare la fine della response
});
// Inviare prima un'intestazione http, i dati successivi vengono inviati in modo asincrono
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
Nota
In questo esempio è stato utilizzato il clientworkerman/http-client
per ottenere i risultati http in modo asincrono e restituire i dati. È possibile utilizzare anche altri client asincroni, come AsyncTcpConnection.