0Pricing
PHP Academy · Lezione

Perché usare la messaggistica asincrona

Scoprite come le code disaccoppiano produttori e consumatori.

Perché usare la messaggistica asincrona è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.

Perché usare la messaggistica asincrona

In una richiesta sincrona, il processo PHP si blocca mentre comunica con gateway per le email, sistemi di pagamento o servizi a valle. Sotto carico, questo lega la latenza e la disponibilità del sistema a ogni dipendenza chiamata. La messaggistica asincrona spezza questa catena: il produttore inserisce un messaggio in una coda e restituisce immediatamente il controllo; i consumatori lo elaborano in seguito, al proprio ritmo.

Questa lezione illustra il perché: disaccoppiamento, buffering e compromessi relativi alle garanzie di consegna da valutare prima di usare RabbitMQ o Kafka.

Disaccoppiamento temporale e spaziale

Una coda disaccoppia produttori e consumatori lungo due assi:

  • Spaziale: nessuno dei due lati deve conoscere l'indirizzo dell'altro; conoscono solo il broker.
  • Temporale: il consumatore può essere inattivo quando il produttore pubblica; il messaggio rimane in attesa.

La versione sincrona qui sotto lega la richiesta web alla disponibilità e alla velocità del server di posta.

<?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');

Pubblicare e proseguire

La versione asincrona salva i dati dell'utente, pubblica un messaggio UserRegistered e restituisce immediatamente il controllo. Un worker separato invia l'email. Ora la latenza HTTP dipende solo dalla rapida pubblicazione su un broker locale, non dal tempo di andata e ritorno 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');

Livellamento del carico (buffering)

I picchi di traffico sono irregolari, mentre la capacità di elaborazione è fissa. Una coda funge da buffer: assorbe un picco di 10.000 messaggi e consente a un pool di worker di smaltirli a una velocità sostenibile. Senza una coda, il picco sovraccaricherebbe direttamente il database o l'API a valle.

Questo è il livellamento del carico: si sacrifica un po' di latenza, perché i messaggi possono rimanere brevemente in attesa, a favore della stabilità, evitando il sovraccarico del sistema.

Garanzie di consegna

Ogni sistema di messaggistica offre una garanzia di consegna. È importante sapere quale:

  • Al massimo una volta: invio senza attesa; i messaggi possono andare persi, ma non vengono mai duplicati.
  • Almeno una volta: i messaggi vengono riconsegnati fino alla conferma; sono possibili duplicati. È il comportamento predefinito più comune.
  • Esattamente una volta: nessuna perdita e nessun duplicato; è costoso e spesso solo un'illusione parziale a livello applicativo.

Poiché la maggior parte dei sistemi reali garantisce almeno una volta, i consumatori devono tollerare la ricezione dello stesso messaggio due volte.

Consumatori idempotenti

La soluzione ai duplicati della consegna almeno una volta è l'idempotenza: elaborare due volte un messaggio produce lo stesso risultato che elaborarlo una sola volta. La tecnica abituale consiste nel memorizzare una chiave di deduplicazione, ovvero l'ID del messaggio, in un indice univoco.

<?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 {}

Conferme e riconsegna

Un consumatore segnala il successo con un ack. Se si arresta prima di inviare l'ack, il broker riconsegna il messaggio a un altro consumatore. È questo il meccanismo che rende possibile la consegna almeno una volta; tuttavia, l'ack deve arrivare dopo il commit dell'effetto collaterale, mai prima.

Se si invia l'ack troppo presto, un arresto può causare la perdita del messaggio. Se lo si invia troppo tardi e si verifica un arresto, si otterrà un duplicato, che il livello di idempotenza assorbirà.

<?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'ordinamento non è gratuito

Le code non garantiscono un ordinamento globale quando si aumentano i consumatori. Due worker che prelevano messaggi dalla stessa coda li elaborano contemporaneamente, quindi il messaggio B può terminare prima del messaggio A.

Se l'ordine è importante, ad esempio per le variazioni del saldo di un conto, è necessario partizionare per chiave, in modo che tutti i messaggi correlati vengano inviati a un singolo consumatore in sequenza. Kafka lo fa nativamente tramite le partizioni; con RabbitMQ, si utilizza un hash coerente per instradare i messaggi verso code separate per chiave.

Dead letter queue

Alcuni messaggi non possono mai essere elaborati correttamente: payload malformati o riferimenti a righe eliminate, ad esempio. Ritentarli all'infinito blocca la coda: si tratta di un poison message. Il modello prevede una dead letter queue (DLQ): dopo N tentativi falliti, il messaggio viene instradato altrove per essere esaminato, invece di essere riconsegnato.

<?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 {}

Quando NON usare una coda

La messaggistica asincrona comporta costi operativi concreti: un broker da gestire, la consistenza eventuale da spiegare al team di prodotto e un debugging più complesso tra processi diversi.

Ricorra a una coda quando il lavoro è lento, soggetto a picchi, ritentabile o fire-and-forget. Lo mantenga sincrono quando il chiamante ha realmente bisogno del risultato immediatamente, ad esempio di un prezzo autorevole che l'utente deve visualizzare: inserire in una coda una chiamata che richiede una risposta aggiunge solo latenza e complessità.

Coda o log

Due forme generali di broker supportano questi modelli, ed entrambe verranno utilizzate nel resto del corso:

  • Una task queue (RabbitMQ) elimina un messaggio dopo che è stato confermato con un ack. È ideale per distribuire il lavoro a un pool di consumatori concorrenti, con instradamento per messaggio e TTL.
  • Un commit log (Kafka) conserva i messaggi in base alla politica di retention; ogni consumatore tiene traccia del proprio offset e può riprodurre lo storico, mentre molti gruppi di consumatori indipendenti leggono lo stesso stream.

Scelga la coda per distribuire il lavoro e il log per gli stream di eventi ad alto throughput e la riproduzione dello storico.

<?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";

Verifica rapida

Ragionare sulle garanzie di consegna.

Ripasso

Ora dispone del modello mentale alla base della messaggistica asincrona:

  • Le code offrono disaccoppiamento spaziale e temporale e fungono da buffer per il livellamento del carico.
  • La maggior parte dei sistemi garantisce almeno una volta, quindi i consumatori devono essere idempotenti.
  • Invii l'ack dopo il commit dell'effetto collaterale e lasci che gli errori provochino la riconsegna.
  • L'ordinamento richiede il partizionamento per chiave; i messaggi velenosi richiedono una DLQ.
  • Non inserisca in coda il lavoro di cui il chiamante ha bisogno con una risposta sincrona.

Ora metterà in pratica questi concetti con RabbitMQ in PHP.

Domande Frequenti

La lezione «Perché usare la messaggistica asincrona» è gratuita?

Sì — il testo completo di «Perché usare la messaggistica asincrona» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.

Cosa imparerò in «Perché usare la messaggistica asincrona»?

Scoprite come le code disaccoppiano produttori e consumatori. Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare PHP Academy?

Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Perché usare la messaggistica asincrona»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione PHP Academy?

Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Perché usare la messaggistica asincrona
  2. Utilizzare RabbitMQ in PHP
  3. Apache Kafka con PHP
  4. Creare flussi di lavoro basati sugli eventi
← Torna a PHP Academy