Históricamente, la Alta Disponibilidad (HA) en IBM MQ dependía de almacenamiento compartido o de replicación externa (RDQM). En las arquitecturas modernas de microservicios y nube (Kubernetes, OpenShift, Docker), el almacenamiento compartido introduce complejidad y latencia.
El Native HA utiliza un algoritmo de consenso (Raft) para replicar datos entre tres instancias independientes. Este laboratorio demuestra cómo levantar un clúster resiliente de 3 nodos usando Docker Compose, utilizando archivos de configuración (qm.ini) montados mediante volúmenes para garantizar el 100 % de fiabilidad en la versión 9.4+. Además, demostraremos el Automatic Client Reconnect (ACR) utilizando un cuarto nodo como cliente.
¿Cómo funciona MQ Native HA?
MQ Native HA fue diseñado para eliminar la dependencia de las tecnologías de almacenamiento compartido (como NFS o SAN), que son frecuentemente complejas y lentas en entornos de nube.
1. El protocolo Raft y el quórum
Native HA se basa en el algoritmo de consenso Raft. En un grupo de tres instancias, los nodos se comunican continuamente para elegir un Líder (Active). Las otras dos instancias se convierten en Réplicas.
- Quórum: Para que el clúster acepte mensajes, la mayoría de los nodos (2 de 3) debe estar funcional y en comunicación. Esto evita el "Split-brain", donde dos nodos podrían intentar ser activos simultáneamente, corrompiendo los datos.
- Elección automática: Si el Líder falla, las Réplicas detectan la ausencia de "heartbeats" e inician una nueva elección. El nodo con el registro de recuperación más actualizado es elegido como nuevo Líder.
2. Replicación síncrona
A diferencia de otras soluciones, MQ Native HA replica los datos al nivel del registro de recuperación. Cuando una aplicación envía un mensaje persistente: 1. El Líder escribe el mensaje en su registro local. 2. El Líder envía los datos del registro a las Réplicas. 3. En cuanto al menos una Réplica confirma la recepción (garantizando la mayoría), el Líder confirma el éxito a la aplicación.
3. Limitaciones y comportamiento de las réplicas
Es fundamental comprender que las Réplicas no son "nodos activos de lectura". Existen limitaciones operativas estrictas:
- Estado de Standby: Las Réplicas están en un estado de "espera en caliente". No procesan mensajes ni permiten que las aplicaciones se conecten a ellas (vía canales o localmente).
- Sin conectividad de aplicación: Si intenta conectar una aplicación a una Réplica, recibirá el error "Queue Manager Not Available" (MQRC_Q_MGR_NOT_AVAILABLE).
- Administración limitada: Comandos como
runmqsctienen una funcionalidad muy restringida en las Réplicas, sirviendo únicamente para consultar el estado del HA.
4. Automatic Client Reconnect (ACR)
El Automatic Client Reconnect (ACR) es una funcionalidad de las bibliotecas del cliente IBM MQ que permite la resiliencia transparente del lado de la aplicación.
Cómo funciona:
- Transparencia: Si la conexión se interrumpe, el cliente MQ suspende la operación de la aplicación en lugar de devolver un error inmediato.
- Reintento automático: El cliente MQ consulta la lista de nombres de conexión (
CONNAME) configurada e intenta restablecer la sesión con los otros nodos. - Failover en Native HA: En un clúster Native HA, el cliente intentará conectarse a las Réplicas (que rechazarán la conexión) hasta encontrar el nuevo Líder (Active). Una vez conectado, el procesamiento se reanuda automáticamente, preservando la integridad de los mensajes.
Qué ocurre técnicamente en el cliente MQI:
- Conexión elegible para reconexión: El cliente debe usar transporte client y una lista de direcciones alternativas, normalmente mediante
CONNAME, CCDT,MQSERVERomqclient.ini. - Reconexión inline: Cuando se detecta el fallo, el cliente intenta restablecer la conexión sin obligar a la aplicación a ejecutar un nuevo
MQCONNoMQCONNX. - Restauración de contexto: Si la reconexión tiene éxito, los handles de conexión y de objetos son recreados por el cliente. Para muchas aplicaciones MQI, esto significa la reanudación del procesamiento con un impacto mínimo.
- Espera más larga durante la llamada MQI: Si el fallo se produce en medio de una llamada, la aplicación puede observar únicamente una espera prolongada hasta que la operación termine o falle definitivamente.
- No todas las APIs se comportan igual: En este laboratorio utilizaremos
amqsphac, un sample de IBM MQ diseñado específicamente para demostrar la reconexión automática en escenarios de alta disponibilidad. El sample usaMQCNO_RECONNECTen elMQCONNXy mantiene el bucle de la aplicación activo durante la reconexión — algo que los samples genéricos comoamqsputcno hacen. El ACR en sentido MQI no está soportado por las IBM MQ classes for Java; para JMS existe un mecanismo propio de reconexión automática.
Anatomía de la configuración (qm.ini)
La configuración lógica de Native HA reside en las stanzas NativeHALocalInstance y NativeHAInstance, que forman parte de la configuración del queue manager. En instalaciones Linux convencionales, esto significa editar el qm.ini de cada instancia.
En este laboratorio con contenedores, mantendremos esas stanzas en archivos dedicados node1.ini, node2.ini y node3.ini, montados como /etc/mqm/nativeha.ini. Lo importante es el contenido de las stanzas, no el nombre del archivo en el host. La imagen del contenedor consume ese archivo montado para inicializar la configuración de Native HA.
La configuración se divide en dos secciones principales:
NativeHALocalInstance
Define la identidad del nodo actual.
- Name: El nombre único de esta instancia (ej:
node1).
NativeHAInstance
Define todos los miembros que participan en el grupo HA. Debe haber una entrada para cada uno de los 3 nodos.
- Name: Nombre único de la instancia.
- ReplicationAddress: La dirección IP o nombre de host y el puerto dedicado exclusivamente al tráfico de replicación de Raft.
Lo que construye este laboratorio
Al final de este laboratorio, tendrá:
- Un clúster de 3 contenedores MQ comunicándose a través de la red de Docker.
- Configuración basada en archivos con stanzas equivalentes a
qm.ini, simulando despliegues empresariales. - Un nodo de Cliente dedicado que demuestra la reconexión automática (ACR).
- Replicación síncrona de registros sin necesidad de almacenamiento compartido.
Preparación del entorno: Instalación del software
Antes de comenzar el laboratorio, debe asegurarse de tener las herramientas de contenedores necesarias y acceso a la imagen oficial de MQ.
También necesita una de estas dos condiciones en el host Linux:
- acceso a
sudo - o pertenencia al grupo
docker, para ejecutar Docker sinsudo
Si no dispone de ninguna de estas opciones, no podrá ejecutar este laboratorio tal como está descrito.
1. Instalar Docker y Docker Compose
Docker es la plataforma base para este laboratorio. Docker Compose permite orquestar los 3 nodos MQ de forma sencilla.
- Windows/macOS: Instale Docker Desktop. Docker Compose ya viene incluido.
- Linux (Ubuntu/Debian):
# Ensure curl is installed
sudo apt-get update && sudo apt-get install -y curl
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Install Docker Compose
sudo apt-get install -y docker-compose-plugin- Linux (RHEL/CentOS/Fedora):
# Remove old versions
sudo dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
# Setup the repository
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
# Install Docker and Compose
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Start the service
sudo systemctl enable --now dockerConfirme la instalación:
docker version
docker compose versionConfiguración de permisos (Linux)
Si recibe un error de "permiso denegado" al ejecutar comandos de Docker, su usuario debe añadirse al grupo docker:
sudo usermod -aG docker $USERNota: Debe ejecutar sudo newgrp docker o cerrar sesión y volver a entrar para aplicar los cambios.
Si prefiere no modificar todavía los grupos del sistema, puede simplemente ejecutar los comandos de este laboratorio con sudo, tal como ya aparecen en los bloques ejecutados en el host.
Confirme antes de continuar:
docker versionSi este comando falla y tampoco puede obtener acceso al grupo docker, deténgase aquí y resuelva primero el acceso al daemon de Docker.
2. Obtener la imagen de IBM MQ
Basta con ejecutar el comando:
docker pull icr.io/ibm-messaging/mq:latest1. Crear los archivos de configuración
Nodos MQ (.ini)
Crearemos tres archivos de configuración distintos para cada nodo.
Cree el archivo para el node1:
cat > node1.ini <<'EOF'
NativeHALocalInstance:
Name=node1
NativeHAInstance:
Name=node1
ReplicationAddress=node1(5000)
NativeHAInstance:
Name=node2
ReplicationAddress=node2(5000)
NativeHAInstance:
Name=node3
ReplicationAddress=node3(5000)
EOFCree el archivo para el node2:
cat > node2.ini <<'EOF'
NativeHALocalInstance:
Name=node2
NativeHAInstance:
Name=node1
ReplicationAddress=node1(5000)
NativeHAInstance:
Name=node2
ReplicationAddress=node2(5000)
NativeHAInstance:
Name=node3
ReplicationAddress=node3(5000)
EOFCree el archivo para el node3:
cat > node3.ini <<'EOF'
NativeHALocalInstance:
Name=node3
NativeHAInstance:
Name=node1
ReplicationAddress=node1(5000)
NativeHAInstance:
Name=node2
ReplicationAddress=node2(5000)
NativeHAInstance:
Name=node3
ReplicationAddress=node3(5000)
EOFArchivo de configuración MQ (config.mqsc)
Cree el archivo con toda la configuración de seguridad y cola. La imagen Docker de IBM MQ ejecuta automáticamente los archivos .mqsc montados en /etc/mqm/ al arrancar el nodo activo — las réplicas reciben la misma configuración por replicación Raft:
cat > config.mqsc <<'EOF'
DEFINE CHANNEL(DEV.APP.SVRCONN) CHLTYPE(SVRCONN) REPLACE
ALTER CHANNEL(DEV.APP.SVRCONN) CHLTYPE(SVRCONN) MCAUSER('mqm')
SET CHLAUTH(DEV.APP.SVRCONN) TYPE(BLOCKUSER) USERLIST('nobody') ACTION(REPLACE)
ALTER QMGR CHLAUTH(DISABLED)
ALTER QMGR CONNAUTH('')
REFRESH SECURITY(*) TYPE(CONNAUTH)
DEFINE QLOCAL(HA.TEST.QUEUE) DEFPSIST(YES) REPLACE
EOF2. El archivo de orquestación (Clúster + Cliente)
Recree el archivo:
rm -f docker-compose.yamlDespués, abra el archivo:
vi docker-compose.yamlY pegue exactamente este contenido:
services:
mq-node1:
container_name: mq-node1
hostname: node1
image: icr.io/ibm-messaging/mq:latest
environment:
LICENSE: "accept"
MQ_QMGR_NAME: "QM_HA"
MQ_NATIVE_HA: "true"
MQ_NATIVE_HA_INSTANCE_NAME: "node1"
volumes:
- ./node1.ini:/etc/mqm/nativeha.ini
- ./config.mqsc:/etc/mqm/20-config.mqsc
ports:
- "1414:1414"
mq-node2:
container_name: mq-node2
hostname: node2
image: icr.io/ibm-messaging/mq:latest
environment:
LICENSE: "accept"
MQ_QMGR_NAME: "QM_HA"
MQ_NATIVE_HA: "true"
MQ_NATIVE_HA_INSTANCE_NAME: "node2"
volumes:
- ./node2.ini:/etc/mqm/nativeha.ini
- ./config.mqsc:/etc/mqm/20-config.mqsc
ports:
- "1415:1414"
mq-node3:
container_name: mq-node3
hostname: node3
image: icr.io/ibm-messaging/mq:latest
environment:
LICENSE: "accept"
MQ_QMGR_NAME: "QM_HA"
MQ_NATIVE_HA: "true"
MQ_NATIVE_HA_INSTANCE_NAME: "node3"
volumes:
- ./node3.ini:/etc/mqm/nativeha.ini
- ./config.mqsc:/etc/mqm/20-config.mqsc
ports:
- "1416:1414"
mq-client:
container_name: mq-client
image: icr.io/ibm-messaging/mq:latest
environment:
LICENSE: "accept"
command: sleep infinity3. Iniciar el clúster
Inicie los contenedores:
docker compose down -v
docker compose up -dEspere unos segundos y confirme que el clúster está estable y que el archivo config.mqsc fue aplicado:
for c in mq-node1 mq-node2 mq-node3; do echo "== $c ==" && docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null || true; doneLo esperado es observar un nodo con ROLE(Active) y los otros dos con ROLE(Replica). Si los contenedores aún se están inicializando, espere unos segundos más y repita.
Identifique el nodo activo y confirme que la cola y el canal fueron creados automáticamente por el config.mqsc:
ACTIVE_NODE=$(for c in mq-node1 mq-node2 mq-node3; do docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null | grep -q "ROLE(Active)" && echo "$c" && break; done) && echo "Active node: $ACTIVE_NODE"docker exec "$ACTIVE_NODE" bash -lc 'echo "DISPLAY QLOCAL(HA.TEST.QUEUE) CURDEPTH" | runmqsc QM_HA'docker exec "$ACTIVE_NODE" bash -lc 'echo "DISPLAY CHANNEL(DEV.APP.SVRCONN) MCAUSER" | runmqsc QM_HA'4. Prueba de quórum y replicación síncrona
En esta primera fase, vamos a demostrar que el clúster sobrevive y mantiene los datos consistentes internamente.
Paso 1: Colocar un mensaje en el Líder
Identifique cuál es el nodo activo y guárdelo en una variable:
ACTIVE_NODE=$(
for c in mq-node1 mq-node2 mq-node3; do
if docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null | grep -q "ROLE(Active)"; then
echo "$c"
break
fi
done
)
echo "Active node: $ACTIVE_NODE"Después, coloque un mensaje en ese nodo:
docker exec -it "$ACTIVE_NODE" /opt/mqm/samp/bin/amqsput HA.TEST.QUEUE QM_HAEscriba: "Validando replicación síncrona" y pulse Enter dos veces.
Paso 2: Simular un fallo (Stop Container)
Detenga el contenedor que está activo:
docker stop "$ACTIVE_NODE"Paso 3: Verificar la elección y la consistencia
Compruebe quién es el nuevo líder y guárdelo en una variable:
NEW_ACTIVE_NODE=$(
for c in mq-node1 mq-node2 mq-node3; do
if docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null | grep -q "ROLE(Active)"; then
echo "$c"
break
fi
done
)
echo "New active node: $NEW_ACTIVE_NODE"Recupere allí el mensaje:
docker exec -it "$NEW_ACTIVE_NODE" /opt/mqm/samp/bin/amqsget HA.TEST.QUEUE QM_HAEl éxito demuestra que el mensaje fue replicado al registro local del nuevo líder antes de la caída del nodo originalmente activo.
5. Demostración de ACR (Automatic Client Reconnect)
Ahora que hemos validado el backend, vamos a probar la resiliencia del lado de la aplicación con el sample amqsphac, que usa MQCNO_RECONNECT internamente y mantiene el bucle de envío activo durante y después del failover.
Paso 1: Garantizar que el clúster está operativo
docker start mq-node1 && docker start mq-node2 && docker start mq-node3ACTIVE_NODE=$(for c in mq-node1 mq-node2 mq-node3; do docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null | grep -q "ROLE(Active)" && echo "$c" && break; done) && echo "Active node: $ACTIVE_NODE"Paso 2: Crear el script de arranque del sample
Escriba el script línea a línea para evitar problemas con el pegado de comandos multilínea:
docker exec mq-client bash -c 'echo "#!/bin/bash" > /tmp/acr.sh'
docker exec mq-client bash -c 'echo "export MQSERVER=\"DEV.APP.SVRCONN/TCP/node1(1414),node2(1414),node3(1414)\"" >> /tmp/acr.sh'
docker exec mq-client bash -c 'echo "/opt/mqm/samp/bin/amqsphac HA.TEST.QUEUE QM_HA" >> /tmp/acr.sh'
docker exec mq-client bash -c 'chmod +x /tmp/acr.sh'Paso 3: Iniciar el sample en segundo plano
docker exec -d mq-client bash -c '/tmp/acr.sh'El amqsphac no produce salida línea a línea en modo no interactivo (buffering de stdout), por lo que la verificación se realiza mediante la profundidad de la cola. Confirme que los mensajes están llegando al nodo activo:
sleep 5 && docker exec "$ACTIVE_NODE" bash -lc 'echo "DISPLAY QLOCAL(HA.TEST.QUEUE) CURDEPTH" | runmqsc QM_HA'El CURDEPTH debe estar creciendo continuamente.
Paso 4: Provocar el fallo del nodo activo
docker stop "$ACTIVE_NODE"Paso 5: Verificar la elección del nuevo líder
NEW_ACTIVE_NODE=$(for c in mq-node1 mq-node2 mq-node3; do docker exec "$c" dspmq -o nativeha -m QM_HA 2>/dev/null | grep -q "ROLE(Active)" && echo "$c" && break; done) && echo "New active node: $NEW_ACTIVE_NODE"Paso 6: Confirmar la reconexión automática mediante el crecimiento de la cola
Espere unos 10 segundos para que la elección se complete y verifique el CURDEPTH en el nuevo líder:
sleep 10 && docker exec "$NEW_ACTIVE_NODE" bash -lc 'echo "DISPLAY QLOCAL(HA.TEST.QUEUE) CURDEPTH" | runmqsc QM_HA'Si el CURDEPTH está creciendo en el nuevo líder, el amqsphac se reconectó automáticamente sin ninguna intervención — el ACR funcionó.
Paso 7: Confirmar los mensajes recibidos
docker exec -it "$NEW_ACTIVE_NODE" /opt/mqm/samp/bin/amqsget HA.TEST.QUEUE QM_HAConclusiones clave para Docker
- Resiliencia por capas: Validamos primero la replicación de datos y después la continuidad de la aplicación.
- ACR & Native HA: La combinación perfecta para arquitecturas de alta disponibilidad total. El
amqsphacusaMQCNO_RECONNECTpara demostrar la reconexión transparente que una aplicación real debe implementar. - Configuración robusta: El uso de volúmenes para montar las stanzas de configuración de Native HA es el enfoque más fiable.
Cleanup
Al final del laboratorio, puede eliminar los contenedores y los archivos creados durante la práctica:
docker compose down -v
rm -f node1.ini node2.ini node3.ini config.mqsc docker-compose.yamlEste cleanup no desinstala Docker, Docker Compose ni la imagen de IBM MQ. Solo elimina los artefactos locales utilizados en este laboratorio.