Todos los productos
Search
Centro de documentos

ApsaraMQ for RocketMQ:Mensajes transaccionales

Última actualización: Sep 04, 2026

Los mensajes transaccionales son un tipo de mensaje especial proporcionado por ApsaraMQ for RocketMQ que garantiza que tanto la transacción local como la entrega del mensaje se completen correctamente o fallen en conjunto. Este mecanismo de confirmación en dos fases mantiene sincronizado el servicio principal con sus consumidores posteriores, sin la sobrecarga de bloqueo de recursos que implican las transacciones distribuidas de arquitectura extendida (XA).

Distributed transaction requirements

Utilice mensajes transaccionales cuando:

  • Un sistema de pedidos deba actualizar su base de datos y notificar a los servicios de logística, puntos y carrito de forma atómica.

  • Un servicio de pagos deba registrar un débito y publicar un evento para los consumidores de libros contables posteriores.

  • La entrega de un mensaje sin completar la transacción local (o viceversa) dejaría al sistema en un estado inconsistente.

Funcionamiento de los mensajes transaccionales

Limitaciones de los mensajes normales

Combinar una transacción local de base de datos con el envío de un mensaje normal crea una brecha donde una operación puede completarse sin la otra:

  • El mensaje se envía, pero la transacción local falla. Los consumidores posteriores actúan sobre un cambio no confirmado.

  • La transacción local se confirma, pero el envío del mensaje falla. Los consumidores posteriores nunca se enteran del cambio.

  • Se produce un tiempo de espera agotado y ni el productor ni el broker pueden determinar si deben confirmar o revertir la operación.

Normal message solution

Costo elevado de las transacciones XA

El protocolo XA coordina transacciones distribuidas entre sistemas, pero bloquea los recursos durante toda la duración de la transacción. A medida que aumenta el número de sistemas participantes, se incrementa la contención por bloqueos y disminuye el rendimiento.

Confirmación en dos fases con mensajes parciales

Los mensajes transaccionales de ApsaraMQ for RocketMQ utilizan un protocolo de confirmación en dos fases que evita ambos problemas:

Transactional message solution

  1. Envío de un mensaje parcial. El productor envía un mensaje al broker. El broker lo almacena y devuelve una confirmación (ACK) al productor. El mensaje se marca como no listo para entrega; un mensaje en este estado se denomina mensaje parcial. Los consumidores posteriores aún no pueden verlo.

  2. Ejecución de la transacción local. El productor ejecuta su operación local en la base de datos (por ejemplo, actualizar el estado de un pedido de no pagado a pagado).

  3. Confirmación o reversión. El productor reporta el resultado de la transacción local al broker:

    • Confirmación: El broker marca el mensaje parcial como listo para entrega y lo envía a los consumidores.

    • Reversión: El broker descarta el mensaje parcial. Los consumidores nunca lo reciben.

  4. Verificación del estado de la transacción (recuperación). Si el broker no recibe un resultado de confirmación o reversión debido a un fallo de red o al reinicio del productor, envía una consulta de estado a una instancia del productor en el clúster. El productor comprueba el resultado de la transacción local y lo reporta nuevamente al broker.

Transaction status check workflow

Nota

Para consultar el intervalo de consulta y el número máximo de reintentos, consulte Parameter limits.

Ciclo de vida del mensaje

Un mensaje transaccional pasa por los siguientes estados:

Transactional message lifecycle

Estado

Descripción

Inicialización

El productor construye el mensaje parcial y se prepara para enviarlo al broker.

Transacción pendiente de confirmación

El broker almacena el mensaje parcial en el sistema de almacenamiento de transacciones. A diferencia de un mensaje normal, el broker no persiste el mensaje parcial de la manera estándar. El mensaje es invisible para los consumidores.

Confirmado para consumo

La transacción local se completa correctamente. El broker almacena el mensaje parcial en el sistema de almacenamiento y lo hace visible para los consumidores.

Reversión del mensaje

La transacción local falla. El broker descarta el mensaje parcial. El flujo de trabajo finaliza.

En proceso de consumo

Un consumidor recoge el mensaje y comienza a procesarlo. Si el consumidor no devuelve un resultado dentro del tiempo de espera configurado, ApsaraMQ for RocketMQ reintenta la entrega. Para más detalles, consulte Consumption retry.

Confirmación del resultado de consumo

El consumidor confirma el resultado del consumo. El mensaje se marca como consumido, pero no se elimina de inmediato.

Eliminación del mensaje

El período de retención del mensaje caduca o el espacio de almacenamiento se agota. ApsaraMQ for RocketMQ elimina los mensajes más antiguos de forma rotativa. Consulte Message storage and cleanup.

De forma predeterminada, ApsaraMQ for RocketMQ retiene todos los mensajes. Un mensaje consumido no se elimina inmediatamente; los consumidores pueden volver a consumirlo hasta que expire el período de retención o se libere espacio de almacenamiento.

Envío de mensajes transaccionales (Java)

Requisitos previos

Antes de empezar, asegúrese de contar con lo siguiente:

  • Un tema con MessageType establecido en Transaction en la consola de ApsaraMQ for RocketMQ.

  • El endpoint de la instancia (disponible en la pestaña Endpoints de la página Instance Details)

  • (Si aplica) El nombre de usuario y la contraseña de la instancia (disponibles en la pestaña Intelligent Authentication de la página Access Control)

Diferencias respecto a los mensajes normales

El envío de un mensaje transaccional difiere del envío de un mensaje normal en dos aspectos:

  • Se requiere un verificador de transacciones. Registre un verificador de transacciones al construir el productor. El verificador se ejecuta automáticamente si el broker consulta el estado de la transacción tras un fallo.

  • Se requiere vinculación del tema. Vincule el tema destino al productor durante la construcción para que el verificador integrado pueda recuperar el estado de la transacción.

Código de ejemplo

Construya un productor con un verificador de transacciones, inicie una transacción, envíe un mensaje parcial, ejecute la transacción local y luego confirme o revierta la operación.

Código de ejemplo

import java.time.Duration;
import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;
import org.apache.rocketmq.client.apis.producer.Transaction;
import org.apache.rocketmq.client.apis.producer.TransactionResolution;
import org.apache.rocketmq.client.java.message.MessageBuilderImpl;
import org.apache.rocketmq.client.apis.message.MessageBuilder;
import org.apache.rocketmq.shaded.com.google.common.base.Strings;

public class ProducerTransactionMessageExample {

    // Simulates checking whether the order exists in the database.
    private static boolean checkOrderById(String orderId) {
        return true;
    }

    // Simulates the local transaction (e.g., inserting an order record).
    private static boolean doLocalTransaction() {
        return true;
    }

    public static void main(String[] args) throws ClientException {
        // Replace with your instance endpoint.
        // Find this on the Endpoints tab of the Instance Details page
        // in the ApsaraMQ for RocketMQ console.
        String endpoints = "<your-instance-endpoint>";

        // The topic must have MessageType set to Transaction.
        String topic = "<your-transaction-topic>";

        ClientServiceProvider provider = ClientServiceProvider.loadService();
        ClientConfigurationBuilder builder = ClientConfiguration.newBuilder()
            .setEndpoints(endpoints);

        // Authentication:
        // - Public endpoint: specify username and password (find these on the
        //   Intelligent Authentication tab of the Access Control page).
        // - VPC endpoint on ECS: no credentials needed; the broker resolves
        //   them from the VPC.
        // - Serverless instance: always specify credentials, regardless of
        //   access method.
        builder.setCredentialProvider(
            new StaticSessionCredentialsProvider("<your-username>", "<your-password>"));
        builder.setRequestTimeout(Duration.ofMillis(5000));
        ClientConfiguration configuration = builder.build();

        MessageBuilder messageBuilder = new MessageBuilderImpl();

        // Build the producer with a transaction checker.
        // The checker runs when the broker queries a half message whose
        // commit/rollback result was not received.
        Producer producer = provider.newProducerBuilder()
            .setTransactionChecker(messageView -> {
                // Look up the order ID attached to the half message.
                // If the order exists in the database, the local transaction
                // committed successfully. Otherwise, roll back.
                final String orderId = messageView.getProperties().get("OrderId");
                if (Strings.isNullOrEmpty(orderId)) {
                    return TransactionResolution.ROLLBACK;
                }
                return checkOrderById(orderId)
                    ? TransactionResolution.COMMIT
                    : TransactionResolution.ROLLBACK;
            })
            .setTopics(topic)
            .setClientConfiguration(configuration)
            .build();

        // Step 1: Begin a transaction.
        final Transaction transaction;
        try {
            transaction = producer.beginTransaction();
        } catch (ClientException e) {
            e.printStackTrace();
            return;
        }

        // Step 2: Build and send the half message.
        Message message = messageBuilder.setTopic(topic)
            .setKeys("messageKey1")
            .setTag("messageTag")
            // Attach a business ID for the transaction checker to query later.
            .addProperty("OrderId", "xxx")
            .setBody("messageBody".getBytes())
            .build();

        final SendReceipt sendReceipt;
        try {
            sendReceipt = producer.send(message, transaction);
        } catch (ClientException e) {
            // Half message send failed. The transaction ends here.
            return;
        }

        // Step 3: Run the local transaction.
        boolean localTransactionOk = doLocalTransaction();

        // Step 4: Commit or roll back based on the local transaction result.
        if (localTransactionOk) {
            try {
                transaction.commit();
            } catch (ClientException e) {
                // If the commit call fails, the broker will invoke the
                // transaction checker to resolve the status.
                e.printStackTrace();
            }
        } else {
            try {
                transaction.rollback();
            } catch (ClientException e) {
                // Log the error. The broker will invoke the transaction
                // checker to resolve the status.
                e.printStackTrace();
            }
        }
    }
}

Reemplace los siguientes marcadores de posición con sus valores reales:

Marcador de posición

Descripción

Ejemplo

<your-instance-endpoint>

Endpoint de la instancia (disponible en la pestaña Endpoints de la página Instance Details)

xxx-hangzhou.rmq.aliyuncs.com:8080

<your-transaction-topic>

Nombre del tema con MessageType establecido en Transaction

order-tx-topic

<your-username>

Nombre de usuario de la instancia (disponible en la pestaña Intelligent Authentication de la página Access Control)

MjoxODgwNzcwODY5MD****

<your-password>

Contraseña de la instancia

NEh6cm9FVUl****

Para consultar ejemplos completos del SDK en todos los idiomas compatibles, consulte Apache RocketMQ 5.x SDKs.

Mejores prácticas

Minimizar resultados de transacción desconocidos

La verificación del estado de la transacción funciona como una red de seguridad ante fallos durante la confirmación o reversión. Un alto volumen de verificaciones de estado degrada el rendimiento del sistema y retrasa la entrega de mensajes. Diseñe las transacciones locales para que devuelvan un resultado definitivo de confirmación o reversión lo antes posible.

Gestión correcta de transacciones en curso

Cuando el broker consulta el estado de un mensaje parcial y la transacción local aún se está ejecutando, devuelva Unknown en lugar de Commit o Rollback. Devolver un resultado prematuro puede causar inconsistencia en los datos.

Si las verificaciones de estado llegan demasiado pronto porque la transacción local es lenta, considere los siguientes enfoques:

  • Aumentar el retraso de la primera verificación. Configure un intervalo más largo antes de que el broker envíe su primera consulta de estado. Compensación: esto también retrasa la recuperación en caso de transacciones que realmente hayan fallado.

  • Detectar explícitamente el estado en curso. Diseñe la lógica de la transacción local para distinguir entre "en ejecución" y "fallida", de modo que el verificador devuelva el estado correcto.

Límites

Restricción

Detalles

Tipo de tema

Los mensajes transaccionales requieren un tema con MessageType establecido en Transaction.

Un SendReceipt por transacción

Cada transacción admite únicamente un SendReceipt.

Solo consistencia eventual

Los mensajes transaccionales garantizan la consistencia entre la transacción local y la entrega del mensaje. No garantizan consistencia en tiempo real entre los consumidores posteriores. Hasta que se entregue el mensaje, el estado posterior puede ir a la zaga de la transacción anterior. Utilice mensajes transaccionales solo cuando sea aceptable el procesamiento asíncrono posterior.

Responsabilidad del lado del consumidor

ApsaraMQ for RocketMQ garantiza la entrega de los mensajes confirmados, pero cada consumidor posterior debe gestionar correctamente el procesamiento. Implemente lógica de reintento de consumo para manejar fallos transitorios. Consulte Consumption retry.

Tiempo de espera de la transacción

Si el broker no puede determinar el resultado de la transacción después del tiempo de espera configurado y el número máximo de reintentos, revierte el mensaje parcial de forma predeterminada. Consulte Parameter limits.