Entwickeln vor dem Lesen
Bei der Entwicklung von Anwendungen mit Workerman sollten Sie die folgenden Punkte beachten:
I. Unterschiede zwischen Workerman-Entwicklung und normaler PHP-Entwicklung
Abgesehen von den Variablenfunktionen, die mit dem HTTP-Protokoll zusammenhängen und nicht direkt verwendet werden können, gibt es nur wenige Unterschiede zwischen der Workerman-Entwicklung und der normalen PHP-Entwicklung.
1. Unterschiedliche Anwendungsschicht-Protokolle
- Normale PHP-Entwicklung basiert in der Regel auf dem HTTP-Anwendungsschichtprotokoll, wobei der Webserver die Protokollanalyse bereits für den Entwickler durchführt.
-
Workerman unterstützt verschiedene Protokolle und hat derzeit HTTP, WebSocket und andere Protokolle integriert. Workerman empfiehlt Entwicklern, einfachere benutzerdefinierte Protokolle zur Kommunikation zu verwenden.
- Für die Entwicklung mit dem HTTP-Protokoll siehe den Http-Service-Teil.
2. Unterschiede im Anforderungszyklus
- PHP gibt in Webanwendungen nach einer Anfrage alle Variablen und Ressourcen frei.
- Anwendungen, die mit Workerman entwickelt wurden, bleiben nach der ersten Analyse im Speicher resident, so dass Klassendefinitionen, globale Objekte und statische Klassenmitglieder nicht freigegeben werden und somit eine wiederholte Nutzung erleichtert wird.
3. Achten Sie auf die Vermeidung von doppelten Definitionen von Klassen und Konstanten
- Da Workerman die kompilierten PHP-Dateien zwischenspeichert, sollten Sie vermeiden, dass dieselbe Klasse oder dieselbe Konstanten-Definitionsdatei mehrfach mit require/include geladen wird. Es wird empfohlen, require_once/include_once zum Laden von Dateien zu verwenden.
4. Achten Sie auf die Freigabe von Verbindungsressourcen im Singleton-Muster
- Da Workerman globale Objekte und statische Klassenmitglieder nicht nach jeder Anfrage freigibt, enthält das Singleton-Muster, wie z.B. bei Datenbanken, oft eine Datenbankinstanz (die eine Datenbanksocketverbindung enthält), die in statischen Mitgliedern der Datenbank gespeichert wird. Das führt dazu, dass Workerman diese Datenbanksocketverbindung während des Lebenszyklus des Prozesses wiederverwendet. Es ist zu beachten, dass der Datenbankserver möglicherweise eine Verbindung schließt, wenn eine bestimmte Zeit lang keine Aktivitäten festgestellt werden. Bei erneutem Zugriff auf diese Datenbankinstanz kann es zu einem Fehler kommen (Fehlermeldung ähnlich wie mysql gone away). Workerman bietet eine Datenbankklasse mit einer Funktion zur automatischen Wiederverbindung. Entwickler können diese direkt nutzen.
5. Achten Sie darauf, exit und die nicht zu verwenden
- Workerman läuft im PHP-Befehlszeilenmodus. Wenn exit oder die aufgerufen wird, führt dies dazu, dass der aktuelle Prozess beendet wird. Obwohl ein neuer identischer Unterprozess sofort nach dem Beenden des Unterprozesses neu erstellt wird, kann dies dennoch Auswirkungen auf das Geschäft haben.
6. Änderungen am Code erfordern einen Neustart des Dienstes, um wirksam zu werden
Da Workerman resident im Speicher ist, werden die Definitionen von PHP-Klassen und -Funktionen nach einmaligem Laden im Speicher behalten und nicht erneut von der Festplatte geladen. Daher ist es notwendig, den Dienst nach jeder Änderung des Anwendungscodes neu zu starten, um die Änderungen wirksam zu machen.
II. Grundlegende Konzepte, die Sie verstehen sollten
1. TCP-Transportprotokoll
TCP ist ein verbindungsorientiertes, zuverlässiges, auf IP basierendes Transportprotokoll. Ein wichtiges Merkmal des TCP-Transportprotokolls ist, dass es auf Datenströmen basiert. Die Anforderungen des Clients werden kontinuierlich an den Server gesendet. Die vom Server empfangenen Daten sind möglicherweise keine vollständige Anforderung und können auch mehrere Anforderungen zusammenfassen. Daher müssen wir innerhalb dieses kontinuierlichen Datenstroms die Grenzen jeder Anforderung unterscheiden. Das Anwendungsschichtprotokoll definiert in erster Linie eine Reihe von Regeln für die Anforderungsgrenzen, um zu verhindern, dass Anforderungsdaten durcheinander geraten.
2. Anwendungsschichtprotokoll
Anwendungsschichtprotokolle (application layer protocol) definieren, wie Anwendungsprozesse, die auf verschiedenen Endsystemen (Client, Server) laufen, Nachrichten austauschen. Beispiele sind HTTP und WebSocket. Ein einfaches Anwendungsschichtprotokoll könnte wie folgt aussehen: {"module":"user","action":"getInfo","uid":456}\n". Dieses Protokoll kennzeichnet das Ende der Anforderung mit "\n" (beachten Sie, dass "\n" hier einen Zeilenumbruch darstellt), wobei der Nachrichteninhalt ein String ist.
3. Kurzverbindung
Eine Kurzverbindung bezieht sich auf den Aufbau einer Verbindung, wenn es einen Datenverkehr zwischen den beiden Kommunikationsparteien gibt. Nach dem Abschluss der Datenübertragung wird die Verbindung beendet, d.h. jede Verbindung erfüllt nur eine Aufgabe beim Senden. HTTP-Dienste von Webanwendungen verwenden in der Regel Kurzverbindungen.
Für die Entwicklung von Kurzverbindungsanwendungen siehe das Kapitel zum grundlegenden Entwicklungsprozess
4. Langverbindung
Eine Langverbindung ermöglicht es, mehrere Datenpakete über eine Verbindung hinweg zu senden.
Hinweis: Langverbindungsanwendungen müssen ein Heartbeat implementieren, da die Verbindung möglicherweise aufgrund längerer Inaktivität von Firewalls in den Netzwerkgeräten getrennt wird.
Langverbindungen werden häufig bei häufigen operationellen und peer-to-peer-Kommunikationen verwendet. Jede TCP-Verbindung erfordert einen dreistufigen Handshake, was Zeit benötigt. Wenn jede Operation zunächst eine Verbindung aufbaut und dann die Operation ausführt, wird die Verarbeitungsgeschwindigkeit erheblich reduziert. Daher wird bei Langverbindungen die Verbindung bei jedem Vorgang nicht getrennt, sodass die nächsten Datensendungen direkt gesendet werden können, ohne eine TCP-Verbindung aufzubauen. Zum Beispiel wird eine Langverbindung für die Verbindung zu einer Datenbank verwendet. Häufige Kommunikation über Kurzverbindungen kann zu Socket-Fehlern führen und häufige Socket-Erstellungen verschwenden Ressourcen.
Wenn Daten aktiv an den Client gesendet werden müssen, wie in Chat-Anwendungen, Echtzeitspielen und mobilen Push-Anwendungen, sind Langverbindungen erforderlich.
Für die Entwicklung von Langverbindungsanwendungen siehe den Gateway/Worker-Entwicklungsprozess
5. Sanfter Neustart
Der allgemeine Neustartprozess besteht darin, alle Prozesse vollständig zu stoppen und dann neue Dienstprozesse zu erstellen. Während dieses Prozesses gibt es einen kurzen Zeitraum, in dem keine Prozesse Dienstleistungen bereitstellen, was dazu führt, dass die Dienste vorübergehend nicht verfügbar sind. Dies kann bei hoher Concurrent-Last zu fehlgeschlagenen Anfragen führen.
Ein sanfter Neustart stoppt die Prozesse nicht alle auf einmal. Stattdessen wird jeder Prozess nacheinander gestoppt. Nachdem ein Prozess beendet wurde, wird sofort ein neuer Prozess erstellt, um diesen zu ersetzen, bis alle alten Prozesse ersetzt sind.
Ein sanfter Neustart von Workerman kann mit dem Befehl php your_file.php reload erreicht werden und ermöglicht das Aktualisieren der Anwendung, ohne die Dienstqualität zu beeinträchtigen.
Hinweis: Nur Dateien, die in on{...} Rückrufen geladen werden, werden nach einem sanften Neustart automatisch aktualisiert. Dateien, die im Startskript direkt geladen oder hartcodiert sind, werden bei einem reload nicht automatisch aktualisiert.
III. Unterschied zwischen Hauptprozess und Unterprozess
Es ist wichtig zu beachten, ob der Code im Hauptprozess oder im Unterprozess ausgeführt wird. Im Allgemeinen wird Code, der vor dem Aufruf von Worker::runAll(); ausgeführt wird, im Hauptprozess ausgeführt, während der Code, der in onXXX-Rückrufen ausgeführt wird, zum Unterprozess gehört. Beachten Sie, dass der Code, der nach Worker::runAll(); geschrieben wird, niemals ausgeführt wird.
Zum Beispiel der folgende Code
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Läuft im Hauptprozess
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// Der Zuweisungsprozess läuft im Hauptprozess
$tcp_worker->onMessage = function(TcpConnection $connection, $data)
{
// Dieser Teil wird im Unterprozess ausgeführt
$connection->send('hello ' . $data);
};
Worker::runAll();
Hinweis: Initialisieren Sie keine Verbindungsressourcen wie Datenbanken, Memcache oder Redis im Hauptprozess, da die Verbindungen, die im Hauptprozess initialisiert werden, möglicherweise von den Unterprozessen automatisch geerbt werden (insbesondere beim Einsatz von Singletons). Alle Prozesse halten dann dieselbe Verbindung. Daten, die über diese Verbindung vom Server zurückgegeben werden, können von mehreren Prozessen gelesen werden, was zu Dateninkonsistenzen führen kann. Ebenso führt das Schließen einer Verbindung durch einen beliebigen Prozess (z.B. wenn der Hauptprozess im Daemon-Modus beendet wird, was zum Schließen der Verbindung führt) dazu, dass alle Unterprozess-Verbindungen ebenfalls geschlossen werden und unvorhersehbare Fehler auftreten können, wie z.B. mysql gone away Fehler.
Es wird empfohlen, Verbindungsressourcen in onWorkerStart zu initialisieren.