Pourquoi la messagerie asynchrone
Découvrez comment les files d’attente découplent les producteurs des consommateurs.
Pourquoi la messagerie asynchrone est une leçon PHP Academy gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage PHP Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours PHP Academy comprend 4 leçons au total.
Pourquoi utiliser la messagerie asynchrone
Dans une requête synchrone, votre processus PHP reste bloqué lorsqu'il communique avec des passerelles de messagerie, des prestataires de paiement ou des services en aval. Sous forte charge, cela lie votre latence et votre disponibilité à chaque dépendance appelée. La messagerie asynchrone rompt cette chaîne : le producteur dépose un message dans une file d'attente et revient immédiatement ; les consommateurs le traitent plus tard, à leur propre rythme.
Cette leçon explique pourquoi l'utiliser : le découplage, la mise en tampon et les compromis entre garanties de livraison que vous devez évaluer avant d'utiliser RabbitMQ ou Kafka.
Découplage temporel et spatial
Une file d'attente découple les producteurs et les consommateurs selon deux axes :
- Spatial — aucune des deux parties n'a besoin de connaître l'adresse de l'autre ; elles connaissent uniquement le courtier.
- Temporel — le consommateur peut être indisponible lorsque le producteur publie le message ; celui-ci attend.
La version synchrone ci-dessous lie la requête web à la disponibilité et à la rapidité du serveur de messagerie.
<?php
// Synchronous: the HTTP request blocks on SMTP
function registerUser(string $email): void {
saveUser($email);
// If SMTP is slow or down, the user waits or the request fails
sendWelcomeEmail($email); // 800ms blocking call
echo "Registered\n";
}
function saveUser(string $e): void { /* ... */ }
function sendWelcomeEmail(string $e): void { usleep(1); }
registerUser('dev@example.com');Publier et passer à la suite
La version asynchrone enregistre l'utilisateur, publie un message UserRegistered et renvoie la réponse. Un processus de travail distinct envoie le courriel. La latence HTTP dépend désormais uniquement de la publication rapide auprès d'un courtier local, et non de l'aller-retour avec SMTP.
<?php
function registerUser(string $email): void {
saveUser($email);
// Publish a lightweight event; worker handles email later
publish('user.registered', json_encode(['email' => $email]));
echo "Registered (email queued)\n";
}
function saveUser(string $e): void { /* ... */ }
function publish(string $routingKey, string $payload): void {
echo "-> queued $routingKey: $payload\n";
}
registerUser('dev@example.com');Lissage de charge (mise en tampon)
Les pics de trafic sont irréguliers ; la capacité de traitement est fixe. Une file d'attente sert de tampon : elle absorbe une arrivée soudaine de 10 000 messages et permet à un pool de processus de travail de les traiter à un rythme durable. Sans file d'attente, le pic submergerait directement la base de données ou l'API en aval.
C'est le lissage de charge : vous échangez de la latence (les messages peuvent attendre brièvement) contre de la stabilité (rien ne s'effondre).
Garanties de livraison
Tout système de messagerie fait une promesse de livraison. Vous devez savoir laquelle s'applique :
- Au plus une fois — envoyer sans attendre de réponse ; les messages peuvent être perdus, mais ne sont jamais dupliqués.
- Au moins une fois — le message est renvoyé jusqu'à la réception de l'accusé ; les doublons sont possibles. C'est le comportement par défaut le plus courant.
- Exactement une fois — aucune perte ni duplication ; cette garantie est coûteuse et souvent partiellement illusoire au niveau de l'application.
Comme la plupart des systèmes réels offrent une garantie au moins une fois, vos consommateurs doivent accepter de voir deux fois le même message.
Consommateurs idempotents
Le remède aux doublons de la livraison au moins une fois est l'idempotence : traiter deux fois un message produit le même résultat que le traiter une seule fois. La technique habituelle consiste à stocker une clé de déduplication (l'identifiant du message) dans un index unique.
<?php
function handle(array $msg, PDO $pdo): void {
$pdo->beginTransaction();
try {
// Unique constraint on message_id makes the insert the dedup gate
$stmt = $pdo->prepare(
'INSERT INTO processed_messages (id) VALUES (?)'
);
$stmt->execute([$msg['id']]);
} catch (PDOException $e) {
$pdo->rollBack();
echo "Duplicate {$msg['id']} skipped\n";
return; // already handled
}
chargeCustomer($msg['amount']);
$pdo->commit();
}
function chargeCustomer(int $a): void {}Accusés de réception et retransmission
Un consommateur signale sa réussite avec un accusé de réception. S'il s'arrête avant d'envoyer l'accusé, le courtier retransmet le message à un autre consommateur. C'est ce qui permet la livraison au moins une fois, mais cela signifie que l'ack doit être envoyé après la validation de l'effet secondaire, jamais avant.
Envoyez l'accusé trop tôt et un arrêt fera perdre le message. Envoyez-le trop tard (puis le processus s'arrête) et vous obtiendrez un doublon, que votre couche d'idempotence absorbera.
<?php
// Pseudocode of the consumer contract
function consumeLoop($channel): void {
while ($msg = $channel->get()) {
try {
processSideEffect($msg); // commit DB write first
$channel->ack($msg); // only then ack
} catch (\Throwable $e) {
$channel->nack($msg, requeue: true); // let it redeliver
}
}
}
function processSideEffect($m): void {}L'ordre n'est pas gratuit
Les files d'attente ne garantissent pas un ordre global lorsque vous augmentez le nombre de consommateurs. Deux processus de travail qui récupèrent des messages dans la même file les traitent simultanément ; le message B peut donc se terminer avant le message A.
Si l'ordre est important (par exemple pour les variations de solde d'un compte), vous devez partitionner par clé afin que tous les messages associés soient envoyés à un seul consommateur dans l'ordre. Kafka le fait nativement avec des partitions ; avec RabbitMQ, vous acheminez les messages à l'aide d'un hachage cohérent vers des files par clé.
Files d'attente des messages non distribuables
Certains messages ne pourront jamais être traités correctement : contenu mal formé, références vers des lignes supprimées. Les réessayer indéfiniment bloque la file d'attente (c'est un message empoisonné). Le modèle de la file d'attente des messages non distribuables (DLQ) consiste, après N tentatives infructueuses, à mettre le message à part pour l'inspecter au lieu de le retransmettre.
<?php
function consume(array $msg, $channel): void {
$attempts = ($msg['headers']['x-attempt'] ?? 0) + 1;
try {
process($msg);
$channel->ack($msg);
} catch (\Throwable $e) {
if ($attempts >= 5) {
$channel->deadLetter($msg); // park in DLQ
} else {
$channel->republish($msg, ['x-attempt' => $attempts]);
}
}
}
function process(array $m): void {}Quand NOT utiliser une file d'attente
La messagerie asynchrone entraîne un véritable coût d'exploitation : il faut gérer un courtier, expliquer la cohérence éventuelle à l'équipe produit et déboguer plus difficilement entre les processus.
Utilisez une file d'attente lorsque le travail est lent, irrégulier, réessayable ou exécuté sans attendre de réponse. Restez synchrone lorsque l'appelant a réellement besoin du résultat immédiatement (par exemple, un prix de référence que l'utilisateur doit voir) : placer dans une file d'attente un appel qui nécessite une réponse ne fait qu'ajouter de la latence et de la complexité.
File d'attente ou journal
Deux grandes architectures de courtiers prennent en charge ces modèles, et la suite de cette formation utilise les deux :
- Une file d'attente de tâches (RabbitMQ) supprime un message dès que l'accusé de réception a été envoyé. Elle excelle dans la répartition du travail entre un pool de consommateurs concurrents, avec un routage par message et des délais d'expiration.
- Un journal de validation (Kafka) conserve les messages pendant la durée de rétention ; chaque consommateur suit sa propre position et peut rejouer l'historique, tandis que de nombreux groupes de consommateurs indépendants lisent le même flux.
Choisissez la file d'attente pour répartir le travail, et le journal pour les flux d'événements à haut débit et leur relecture.
<?php
$useCase = 'replay events for a new analytics service';
$broker = str_contains($useCase, 'replay') || str_contains($useCase, 'stream')
? 'Kafka (commit log)'
: 'RabbitMQ (task queue)';
echo $broker . "\n";Vérification rapide
Raisonnement sur les garanties de livraison.
Récapitulatif
Vous disposez maintenant du modèle mental qui sous-tend la messagerie asynchrone :
- Les files d'attente assurent un découplage spatial et temporel et servent de tampon pour lisser la charge.
- La plupart des systèmes fonctionnent « au moins une fois », les consommateurs doivent donc être idempotents.
- Envoyez l'accusé après la validation de l'effet secondaire ; laissez les échecs provoquer une retransmission.
- Le respect de l'ordre nécessite un partitionnement par clé ; les messages empoisonnés nécessitent une DLQ.
- Ne placez pas en file d'attente le travail auquel l'appelant a besoin d'une réponse synchrone.
Ensuite, vous mettrez ces notions en pratique avec RabbitMQ en PHP.
Questions Fréquemment Posées
La leçon « Pourquoi la messagerie asynchrone » est-elle gratuite ?
Oui — le texte complet de « Pourquoi la messagerie asynchrone » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours PHP Academy, passe à CoddyKit PRO. Le cours PHP Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Pourquoi la messagerie asynchrone » ?
Découvrez comment les files d’attente découplent les producteurs des consommateurs. Tu pratiques PHP Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer PHP Academy ?
Aucune expérience préalable n'est requise. PHP Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.
Combien de temps prend la leçon « Pourquoi la messagerie asynchrone » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon PHP Academy ?
Oui. Chaque leçon PHP Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Pourquoi la messagerie asynchrone
- Travailler avec RabbitMQ en PHP
- Apache Kafka avec PHP
- Créer des flux de travail orientés événements