À lire avant de développer
En utilisant Workerman pour développer des applications, vous devez comprendre les éléments suivants :
I. Les différences entre le développement avec Workerman et le développement PHP classique
À part les variables et fonctions liées au protocole HTTP qui ne peuvent pas être utilisées directement, le développement avec Workerman ne diffère pas beaucoup du développement PHP classique.
1. Différence des protocoles de couche application
- Le développement PHP classique est généralement basé sur le protocole de couche application HTTP, le WebServer ayant déjà aidé le développeur à réaliser l'analyse du protocole.
-
Workerman prend en charge divers protocoles et inclut actuellement des protocoles tels que HTTP et WebSocket. Workerman recommande aux développeurs d'utiliser des protocoles personnalisés plus simples pour la communication.
- Pour le développement basé sur le protocole HTTP, veuillez consulter la section sur le service Http.
2. Différences dans le cycle de demande
- Dans une application Web, PHP libère toutes les variables et ressources après chaque demande.
- Les applications développées avec Workerman résident en mémoire après leur premier chargement et analyse, ce qui signifie que les définitions de classes, objets globaux et membres statiques des classes ne seront pas libérés, facilitant leur réutilisation ultérieure.
3. Attention à éviter les définitions de classes et constantes en double
- Comme Workerman met en cache les fichiers PHP compilés, évitez d'exiger/inclure plusieurs fois le même fichier de définition de classe ou de constante. Il est conseillé d'utiliser require_once/include_once pour charger des fichiers.
4. Attention à la libération des ressources de connexion dans le modèle singleton
- Comme Workerman ne libère pas les objets globaux et les membres statiques des classes après chaque requête, dans un modèle singleton pour des bases de données, il est courant de conserver une instance de base de données (qui contient un socket de connexion à la base de données) en tant que membre statique de la classe de base de données. Cela permet à Workerman de réutiliser ce socket de connexion pendant le cycle de vie du processus. Il est à noter que lorsque le serveur de base de données détecte qu'une connexion est inactive pendant un certain temps, il peut fermer le socket de manière proactive. Ainsi, une nouvelle utilisation de cette instance de base de données peut provoquer une erreur (le message d'erreur ressemble à 'mysql gone away'). Workerman fournit une classe de base de données avec une fonctionnalité de déconnexion et de reconnexion que les développeurs peuvent utiliser directement.
5. Attention à ne pas utiliser les instructions exit et die
- Workerman fonctionne en mode ligne de commande PHP. Lorsque les instructions exit ou die sont appelées, cela entraîne la sortie du processus actuel. Bien que le sous-processus soit immédiatement recréé pour continuer à servir, cela peut toujours nuire aux affaires.
6. Les modifications du code nécessitent un redémarrage du service pour prendre effet
Étant donné que Workerman réside en mémoire, la définition des classes et des fonctions PHP ne sera pas relue depuis le disque après avoir été chargée une fois, donc chaque fois que le code métier est modifié, un redémarrage est nécessaire pour que cela prenne effet.
II. Concepts de base à comprendre
1. Protocole de transport TCP
TCP est un protocole de transport de couche orienté connexion, fiable et basé sur IP. Une caractéristique importante du protocole TCP est qu'il est basé sur le flux de données : les requêtes des clients sont continuellement envoyées au serveur, et les données reçues par le serveur peuvent ne pas constituer une requête complète, mais peuvent aussi être plusieurs requêtes concaténées. Cela nécessite que nous distinguions les limites de chaque requête dans ce flux continu de données. Le protocole de couche application définit principalement un ensemble de règles pour les limites de requête afin d'éviter le désordre des données de requête.
2. Protocole de couche application
Le protocole de couche application (application layer protocol) définit comment les processus d'application sur différents systèmes côté client et serveur échangent des messages, par exemple HTTP et WebSocket font partie des protocoles de couche application. Par exemple, un protocole de couche application simple peut être : {"module":"user","action":"getInfo","uid":456}\n Ce protocole marque la fin de la requête avec "\n" (notez que ici "\n" représente un retour à la ligne), le corps du message est une chaîne.
3. Connexion courte
Une connexion courte consiste à établir une connexion lorsque les deux parties communiquent des données, puis à rompre cette connexion après l'envoi des données, c'est-à-dire que chaque connexion traite une seule pièce de travail. Le service HTTP des sites WEB utilise généralement des connexions courtes.
Le développement d'applications à connexion courte peut se référer au chapitre sur le processus de développement de base
4. Connexion longue
Une connexion longue permet d'envoyer plusieurs paquets de données sur une connexion.
Remarque : Les applications à connexion longue doivent inclure un cœur; sinon, la connexion pourrait être interrompue par le pare-feu d'un nœud de routage en raison d'une inactivité prolongée.
Les connexions longues sont souvent utilisées dans des situations de communication point à point avec des interactions fréquentes. Chaque connexion TCP nécessite un processus d'établissement en trois étapes, ce qui prend du temps; si chaque opération consiste à établir la connexion puis à procéder, la vitesse de traitement sera considérablement réduite. Ainsi, les connexions longues restent actives après chaque opération, permettant un envoi immédiat de paquets de données lors du traitement suivant sans avoir à établir de connexion TCP. Par exemple : les connexions de base de données utilisent des connexions longues ; l'utilisation de connexions courtes avec des communications fréquentes peut entraîner des erreurs de socket, et la création fréquente de sockets gaspille également des ressources.
Lorsque des données doivent être poussées vers le client, par exemple dans des applications de chat, de jeux en temps réel, ou de notifications sur mobile, des connexions longues sont nécessaires.
Le développement d'applications à connexion longue peut se référer au processus de développement Gateway/Worker
5. Redémarrage en douceur
Le processus normal de redémarrage consiste à arrêter tous les processus puis à commencer à créer de nouveaux processus de service. Pendant ce temps, il y a un court laps de temps où aucun processus ne fournit de service, ce qui peut rendre le service temporairement indisponible, entraînant immanquablement des échecs de requêtes en cas de forte concurrence.
Le redémarrage en douceur ne cesse pas tous les processus simultanément, mais arrête un processus à la fois. Après la fermeture de chaque processus, un nouveau processus est immédiatement créé pour le remplacer, jusqu'à ce que tous les anciens processus soient remplacés.
Pour effectuer un redémarrage en douceur dans Workerman, utilisez la commande php your_file.php reload, ce qui permettra de mettre à jour l'application sans affecter la qualité du service.
Remarque : seuls les fichiers chargés dans les rappels on{...} seront automatiquement mis à jour après un redémarrage en douceur; les fichiers chargés directement dans le script de démarrage ou le code codé en dur ne seront pas mis à jour lors de l'exécution de reload.
III. Différence entre processus principal et sous-processus
Il est crucial de noter si le code s'exécute dans le processus principal ou dans un sous-processus. En général, le code exécuté avant l'appel de Worker::runAll(); fonctionne dans le processus principal, alors que le code exécuté dans les rappels onXXX appartient aux sous-processus. Attention, le code écrit après Worker::runAll(); ne sera jamais exécuté.
Par exemple, le code suivant :
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
require_once __DIR__ . '/vendor/autoload.php';
// Exécuté dans le processus principal
$tcp_worker = new Worker("tcp://0.0.0.0:2347");
// L'affectation se déroule dans le processus principal
$tcp_worker->onMessage = function(TcpConnection $connection, $data)
{
// Cette partie s'exécute dans le sous-processus
$connection->send('hello ' . $data);
};
Worker::runAll();
Attention : Il ne faut pas initialiser des connexions à des bases de données, memcache, redis, etc., dans le processus principal, car les connexions initialisées dans le processus principal peuvent être automatiquement héritées par les sous-processus (surtout quand vous utilisez le singleton), tous les processus détenant la même connexion. Les données retournées par le serveur via cette connexion peuvent être lues par plusieurs processus, entraînant des incohérences de données. De la même manière, si un processus ferme une connexion (par exemple, en mode daemon, le processus principal se ferme entraînant la fermeture de la connexion), cela provoquera la fermeture de toutes les connexions dans tous les sous-processus, entraînant des erreurs imprévisibles telles que l'erreur 'mysql gone away'.
Il est recommandé d'initialiser les ressources de connexion dans onWorkerStart.