Traitement des affaires lentes
Parfois, nous devons traiter des affaires lentes. Pour éviter que les affaires lentes n'affectent le traitement d'autres requêtes de webman, ces affaires peuvent être traitées selon différentes solutions en fonction de la situation.
Solution 1 Utiliser une file d'attente de messages
Voir file d'attente redis file d'attente stomp
Avantages
Peut gérer des demandes de traitement d'affaires massives et imprévues.
Inconvénients
Ne peut pas retourner directement les résultats au client. Si des résultats doivent être poussés, cela nécessite d'autres services, comme par exemple utiliser webman/push pour pousser les résultats du traitement.
Solution 2 Ajouter un port HTTP
Ajouter un port HTTP pour traiter les requêtes lentes. Ces requêtes lentes accèdent à ce port pour être traitées par un groupe spécifique de processus, et après traitement, les résultats sont renvoyés directement au client.
Avantages
Peut retourner directement les données au client.
Inconvénients
Ne peut pas gérer des demandes massives et imprévues.
Étapes de mise en œuvre
Ajoutez la configuration suivante dans config/process.php
.
return [
// ... autres configurations omises ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // nombre de processus
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // configuration de la classe request
'logger' => \support\Log::channel('default'), // instance de log
'appPath' => app_path(), // chemin du répertoire app
'publicPath' => public_path() // chemin du répertoire public
]
]
];
Ainsi, l'interface lente peut passer par http://127.0.0.1:8686/
, sans affecter le traitement des affaires des autres processus.
Pour que le frontend ne perçoive pas la différence de port, vous pouvez ajouter un proxy pour le port 8686 dans nginx. Supposons que tous les chemins de requête des interfaces lentes commencent par /tast
, la configuration nginx entière ressemble à ceci :
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# Ajouter un upstream 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;
# Les requêtes commençant par /tast passent par le port 8686, veuillez modifier /tast en fonction de ce dont vous avez besoin
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;
}
# Les autres requêtes passent par le port d'origine 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;
}
}
}
Ainsi, lorsque le client accède à domain.com/tast/xxx
, cela passera par le port 8686 séparé, sans affecter le traitement des requêtes du port 8787.
Solution 3 Utiliser le HTTP chunked pour envoyer des données de manière asynchrone
Avantages
Peut retourner directement les données au client.
Installer 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('')); // Envoi d'un chunk vide pour indiquer la fin de la réponse
});
// Envoyer d'abord un en-tête http, les données suivantes seront envoyées de manière asynchrone
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
Astuce
Dans cet exemple, le clientworkerman/http-client
est utilisé pour obtenir de manière asynchrone le résultat http et renvoyer les données. Vous pouvez également utiliser d'autres clients asynchrones comme AsyncTcpConnection.