Langsame Geschäftsverarbeitung
Manchmal müssen wir langsame Geschäftsabläufe verarbeiten. Um zu vermeiden, dass langsame Geschäftsabläufe die Verarbeitung anderer Anfragen in Webman beeinträchtigen, können je nach Situation unterschiedliche Lösungsansätze verwendet werden.
Ansatz eins: Verwendung einer Nachrichtenwarteschlange
Siehe Redis-Warteschlange STOMP-Warteschlange
Vorteile
Kann plötzliche, massenhafte Geschäftsverarbeitungsanfragen bewältigen.
Nachteile
Es kann kein direktes Ergebnis an den Client zurückgegeben werden. Wenn Ergebnisse gesendet werden müssen, ist die Zusammenarbeit mit anderen Diensten nötig, zum Beispiel mit webman/push, um die Verarbeitungsresultate zu pushen.
Ansatz zwei: Hinzufügen eines HTTP-Ports
Ein neuer HTTP-Port wird hinzugefügt, um langsame Anfragen zu verarbeiten. Diese langsamen Anfragen gelangen über den Zugriff auf diesen Port in eine spezielle Gruppe von Prozessen zur Verarbeitung, wobei das Ergebnis direkt an den Client zurückgegeben wird.
Vorteile
Daten können direkt an den Client zurückgegeben werden.
Nachteile
Kann plötzliche, massenhafte Anfragen nicht bewältigen.
Implementierungsschritte
Fügen Sie in config/process.php
die folgende Konfiguration hinzu.
return [
// ... andere Konfigurationen hier weggelassen ...
'task' => [
'handler' => \Webman\App::class,
'listen' => 'http://0.0.0.0:8686',
'count' => 8, // Anzahl der Prozesse
'user' => '',
'group' => '',
'reusePort' => true,
'constructor' => [
'requestClass' => \support\Request::class, // request-Klasse einstellen
'logger' => \support\Log::channel('default'), // Log-Instanz
'appPath' => app_path(), // Standort des app-Verzeichnisses
'publicPath' => public_path() // Standort des public-Verzeichnisses
]
]
];
Damit können langsame Schnittstellen die Gruppe von Prozessen unter http://127.0.0.1:8686/
verwenden, ohne die Geschäftsverarbeitung anderer Prozesse zu beeinträchtigen.
Um für das Frontend die Portdifferenz unsichtbar zu machen, kann ein Proxy für den Port 8686 in Nginx hinzugefügt werden. Angenommen, die Anforderungs-Pfade der langsamen Schnittstellen beginnen alle mit /tast
, dann könnte die gesamte Nginx-Konfiguration wie folgt aussehen:
upstream webman {
server 127.0.0.1:8787;
keepalive 10240;
}
# Fügen Sie ein weiteres upstream für 8686 hinzu
upstream task {
server 127.0.0.1:8686;
keepalive 10240;
}
server {
server_name webman.com;
listen 80;
access_log off;
root /path/webman/public;
# Anfragen, die mit /tast beginnen, gehen über den Port 8686, bitte ändern Sie /tast entsprechend Ihrer benötigten Präfixe
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;
}
# Andere Anfragen gehen über den ursprünglichen Port 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;
}
}
}
Wenn der Client dann domain.com/tast/xxx
aufruft, wird dies über den separaten Port 8686 verarbeitet, ohne dass die Anfragen auf dem Port 8787 beeinträchtigt werden.
Ansatz drei: Verwendung von HTTP Chunked für asynchrone, segmentweise Datenübertragung
Vorteile
Daten können direkt an den Client zurückgegeben werden.
Installieren Sie 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('')); // Leeren Chunk senden, um das Response zu beenden
});
// Zuerst einen HTTP-Header senden, die nachfolgenden Daten werden asynchron gesendet
return response()->withHeaders([
"Transfer-Encoding" => "chunked",
]);
}
}
Hinweis
In diesem Beispiel wird derworkerman/http-client
verwendet, um asynchron HTTP-Ergebnisse abzurufen und Daten zurückzugeben. Es können auch andere asynchrone Clients verwendet werden, wie z.B. AsyncTcpConnection.