0Pricing
PHP Academy · Lección

Por qué usar mensajería asíncrona

Descubra cómo las colas desacoplan productores y consumidores.

Por qué usar mensajería asíncrona es una lección gratuita de PHP Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de PHP Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de PHP Academy incluye 4 lecciones en total.

Por qué usar mensajería asíncrona

En una solicitud síncrona, el proceso PHP se bloquea mientras se comunica con pasarelas de correo electrónico, procesadores de pagos o servicios posteriores. Con carga, esto vincula su latencia y disponibilidad a cada dependencia que utiliza. La mensajería asíncrona rompe esa cadena: el productor coloca un mensaje en una cola y devuelve el control de inmediato; los consumidores lo procesan más tarde, a su propio ritmo.

Esta lección explica el porqué: el desacoplamiento, el almacenamiento en búfer y las concesiones entre garantías de entrega que debe analizar antes de utilizar RabbitMQ o Kafka.

Desacoplamiento temporal y espacial

Una cola desacopla a productores y consumidores en dos dimensiones:

  • Espacial: ninguna de las partes necesita la dirección de la otra; solo conocen el broker.
  • Temporal: el consumidor puede estar inactivo cuando el productor publica; el mensaje queda a la espera.

La versión síncrona que aparece a continuación acopla la solicitud web al tiempo de actividad y la velocidad del servidor de correo.

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

Publique y continúe

La versión asíncrona guarda al usuario, publica un mensaje UserRegistered y devuelve el control. Un worker independiente envía el correo electrónico. Ahora la latencia HTTP depende únicamente de una publicación rápida en el broker local, no del viaje de ida y vuelta de 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');

Nivelación de carga (buffering)

Los picos de tráfico son irregulares, mientras que la capacidad de procesamiento es fija. Una cola actúa como búfer: absorbe un pico de 10.000 mensajes y permite que un grupo de workers los procese a un ritmo sostenible. Sin una cola, el pico sobrecargaría directamente la base de datos o la API posterior.

Esto es la nivelación de carga: se sacrifica latencia (los mensajes pueden esperar brevemente) a cambio de estabilidad (nada se viene abajo).

Garantías de entrega

Todo sistema de mensajería ofrece una garantía de entrega. Sepa cuál tiene:

  • Como máximo una vez: enviar y olvidar; los mensajes pueden perderse, pero nunca se duplican.
  • Al menos una vez: se vuelven a entregar hasta que se confirman; es posible que haya duplicados. Es la opción predeterminada más habitual.
  • Exactamente una vez: ni pérdidas ni duplicados; es costosa y, a menudo, una ilusión parcial en la capa de aplicación.

Como la mayoría de los sistemas reales ofrecen al menos una vez, sus consumidores deben tolerar recibir el mismo mensaje dos veces.

Consumidores idempotentes

La solución a los duplicados de la entrega al menos una vez es la idempotencia: procesar un mensaje dos veces produce el mismo resultado que procesarlo una sola vez. La técnica habitual consiste en guardar una clave de deduplicación (el ID del mensaje) en un índice único.

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

Confirmaciones y reentrega

Un consumidor indica que la operación tuvo éxito mediante un ack. Si se bloquea antes de enviar la confirmación, el broker vuelve a entregar el mensaje a otro consumidor. Esto es lo que hace posible la entrega al menos una vez, pero significa que el ack debe producirse después de confirmar el efecto secundario, nunca antes.

Confirme demasiado pronto y un bloqueo provocará la pérdida del mensaje. Confirme demasiado tarde (y se produce un bloqueo) y obtendrá un duplicado, que su capa de idempotencia absorberá.

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

El orden tiene un coste

Las colas no garantizan un orden global cuando se amplía el número de consumidores. Dos workers que extraen mensajes de la misma cola los procesan simultáneamente, por lo que el mensaje B puede finalizar antes que el mensaje A.

Si el orden es importante (por ejemplo, para las variaciones del saldo de una cuenta), debe particionar por clave para que todos los mensajes relacionados lleguen a un único consumidor en secuencia. Kafka lo hace de forma nativa mediante particiones; con RabbitMQ, dirija los mensajes mediante un hash consistente a colas por clave.

Colas de mensajes muertos

Algunos mensajes nunca podrán procesarse correctamente: cargas útiles malformadas o referencias a filas eliminadas. Reintentarlos eternamente atasca la cola (un mensaje tóxico). El patrón consiste en una cola de mensajes muertos (DLQ): después de N intentos fallidos, desvíe el mensaje para inspeccionarlo en lugar de volver a entregarlo.

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

Cuándo NO usar una cola

La mensajería asíncrona añade costes operativos reales: un broker que ejecutar, la consistencia eventual que explicar al equipo de producto y una depuración más compleja entre los límites de los procesos.

Opte por una cola cuando el trabajo sea lento, irregular, reintentable o de envío y olvido. Manténgalo síncrono cuando el usuario necesite realmente el resultado ahora (por ejemplo, un precio autorizado que deba ver); envolver en una cola una llamada que necesita una respuesta solo añade latencia y complejidad.

Cola frente a log

Dos formas generales de broker sustentan estos patrones, y el resto de este curso utiliza ambas:

  • Una cola de tareas (RabbitMQ) elimina un mensaje una vez confirmado. Es excelente para distribuir trabajo entre un grupo de consumidores competidores, con enrutamiento por mensaje y TTL.
  • Un commit log (Kafka) conserva los mensajes según la retención; cada consumidor lleva su propio offset y puede reproducir el historial, y muchos grupos de consumidores independientes leen el mismo flujo.

Elija la cola para distribuir trabajo y el log para flujos de eventos de alto rendimiento y su reproducción.

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

Comprobación rápida

Razonamiento sobre las garantías de entrega.

Resumen

Ya tiene el modelo mental en el que se basa la mensajería asíncrona:

  • Las colas proporcionan desacoplamiento espacial y temporal y actúan como búfer para nivelar la carga.
  • La mayoría de los sistemas ofrecen al menos una vez, por lo que los consumidores deben ser idempotentes.
  • Envíe el ack después de confirmar el efecto secundario; permita que los fallos provoquen una reentrega.
  • El orden requiere particionar por clave; los mensajes tóxicos requieren una DLQ.
  • No ponga en una cola el trabajo cuyo resultado el solicitante necesita de forma síncrona.

A continuación, pondrá esto en práctica con RabbitMQ en PHP.

Preguntas frecuentes

¿La lección «Por qué usar mensajería asíncrona» es gratis?

Sí — el texto completo de «Por qué usar mensajería asíncrona» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de PHP Academy, actualiza a CoddyKit PRO. El curso de PHP Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Por qué usar mensajería asíncrona»?

Descubra cómo las colas desacoplan productores y consumidores. Practicas PHP Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar PHP Academy?

No se requiere experiencia previa. PHP Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.

¿Cuánto tiempo toma la lección «Por qué usar mensajería asíncrona»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de PHP Academy?

Sí. Cada lección de PHP Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Por qué usar mensajería asíncrona
  2. Trabajo con RabbitMQ en PHP
  3. Apache Kafka con PHP
  4. Creación de flujos de trabajo basados en eventos
← Volver a PHP Academy