Historicamente, a Alta Disponibilidade (HA) no IBM MQ dependia de storage partilhado ou de replicação externa (RDQM). Em arquiteturas modernas de micro-serviços e cloud (Kubernetes, OpenShift, Docker), o storage partilhado introduz complexidade e latência.
O Native HA utiliza um algoritmo de consenso (Raft) para replicar dados entre três instâncias independentes. Este lab demonstra como subir um cluster resiliente de 3 nós usando Docker Compose, utilizando ficheiros de configuração (qm.ini) montados via volumes para garantir 100% de fiabilidade na versão 9.4+. Além disso, demonstraremos o Automatic Client Reconnect (ACR) utilizando um quarto nó como cliente.
Como funciona o MQ Native HA?
O MQ Native HA foi desenhado para eliminar a dependência de tecnologias de storage partilhado (como NFS ou SAN), que são frequentemente complexas e lentas em ambientes de nuvem.
1. O Protocolo Raft e o Quorum
O Native HA baseia-se no algoritmo de consenso Raft. Num grupo de três instâncias, os nós comunicam continuamente para eleger um Líder (Active). As outras duas instâncias tornam-se Réplicas.
- Quorum: Para que o cluster aceite mensagens, a maioria dos nós (2 em 3) deve estar funcional e em comunicação. Isto evita o "Split-brain", onde dois nós poderiam tentar ser ativos simultaneamente, corrompendo os dados.
- Eleição Automática: Se o Líder falhar, as Réplicas detectam a ausência de "heartbeats" e iniciam uma nova eleição. O nó com o log de recuperação mais atualizado é eleito o novo Líder.
2. Replicação Síncrona
Ao contrário de outras soluções, o MQ Native HA replica os dados ao nível do log de recuperação. Quando uma aplicação envia uma mensagem persistente: 1. O Líder escreve a mensagem no seu log local. 2. O Líder envia os dados do log para as Réplicas. 3. Assim que pelo menos uma Réplica confirma a receção (garantindo a maioria), o Líder confirma o sucesso à aplicação.
3. Limitações e Comportamento das Réplicas
É fundamental compreender que as Réplicas não são "nós ativos de leitura". Existem limitações operacionais estritas:
- Estado de Standby: As Réplicas estão num estado de "espera quente". Não processam mensagens nem permitem que aplicações se liguem a elas (via canais ou localmente).
- Sem Conectividade de Aplicação: Se tentar ligar uma aplicação a uma Réplica, receberá um erro de "Queue Manager Not Available" (MQRC_Q_MGR_NOT_AVAILABLE).
- Administração Limitada: Comandos como
runmqsctêm funcionalidades muito restritas nas Réplicas, servindo apenas para consultar o estado do HA.
4. Automatic Client Reconnect (ACR)
O Automatic Client Reconnect (ACR) é uma funcionalidade das bibliotecas do cliente IBM MQ que permite a resiliência transparente do lado da aplicação.
Como funciona:
- Transparência: Se a ligação for interrompida, o cliente MQ suspende a operação da aplicação em vez de devolver um erro imediato.
- Retry Automático: O cliente MQ consulta a lista de nomes de conexão (
CONNAME) configurada e tenta restabelecer a sessão com os outros nós. - Failover em Native HA: Num cluster Native HA, o cliente tentará ligar-se às Réplicas (que rejeitarão a ligação) até encontrar o novo Líder (Active). Uma vez ligado, o processamento retoma automaticamente, preservando a integridade das mensagens.
O que acontece tecnicamente no cliente MQI:
- Ligação elegível para reconnect: O cliente tem de usar transporte client e uma lista de endereços alternativa, normalmente via
CONNAME, CCDT,MQSERVERoumqclient.ini. - Reconnect inline: Quando a falha é detetada, o cliente tenta restabelecer a ligação sem obrigar a aplicação a executar um novo
MQCONNouMQCONNX. - Restauro de contexto: Se a reconexão for bem-sucedida, os handles de ligação e de objetos são recriados pelo cliente. Para muitas aplicações MQI, isto significa retoma do processamento com impacto mínimo.
- Espera mais longa durante a chamada MQI: Se a falha ocorrer a meio de uma chamada, a aplicação pode observar apenas uma espera prolongada até a operação terminar ou falhar definitivamente.
- Nem todas as APIs se comportam da mesma forma: Neste lab vamos usar
amqsphac, um sample IBM MQ desenhado especificamente para demonstrar reconexão automática em cenários de alta disponibilidade. O sample usaMQCNO_RECONNECTnoMQCONNXe mantém o loop de aplicação ativo durante a reconexão — o que samples genéricos comoamqsputcnão fazem. ACR no sentido MQI não é suportado pelas IBM MQ classes for Java; para JMS existe um mecanismo próprio de reconexão automática.
Anatomia da Configuração (qm.ini)
A configuração lógica do Native HA reside nas stanzas NativeHALocalInstance e NativeHAInstance, que fazem parte da configuração do queue manager. Em instalações Linux convencionais, isto significa editar o qm.ini de cada instância.
Neste lab com contentores, vamos manter essas stanzas em ficheiros dedicados node1.ini, node2.ini e node3.ini, montados como /etc/mqm/nativeha.ini. O importante é o conteúdo das stanzas, não o nome do ficheiro no host. O container image consome esse ficheiro montado para inicializar a configuração do Native HA.
A configuração divide-se em duas secções principais:
NativeHALocalInstance
Define a identidade do nó atual.
- Name: O nome único desta instância (ex:
node1).
NativeHAInstance
Define todos os membros que participam no grupo HA. Deve haver uma entrada para cada um dos 3 nós.
- Name: Nome único da instância.
- ReplicationAddress: O endereço IP ou Hostname e a porta dedicada exclusivamente ao tráfego de replicação do Raft.
O que este lab constrói
No fim deste lab, terá:
- Um cluster de 3 contentores MQ comunicando via rede Docker.
- Configuração baseada em ficheiros com stanzas equivalentes ao
qm.ini, simulando implementações empresariais. - Um nó de Cliente dedicado que demonstra a reconexão automática (ACR).
- Replicação síncrona de logs sem necessidade de storage partilhado.
Preparação do Ambiente: Instalação do Software
Antes de iniciar o lab, deve garantir que tem as ferramentas de containerização necessárias e acesso à imagem oficial do MQ.
Também precisa de uma destas duas condições no host Linux:
- acesso a
sudo - ou pertença ao grupo
docker, para executar Docker semsudo
Se não tiver nenhuma destas opções, não conseguirá executar este lab tal como está descrito.
1. Instalar Docker e Docker Compose
O Docker é a plataforma base para este lab. O Docker Compose permite orquestrar os 3 nós MQ de forma simples.
- Windows/macOS: Instale o Docker Desktop. O Docker Compose já vem incluído.
- 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 a instalação:
docker version
docker compose versionConfiguração de Permissões (Linux)
Se receber um erro de "permission denied" ao executar comandos do Docker, o seu utilizador precisa de ser adicionado ao grupo docker:
sudo usermod -aG docker $USERNota: Deve executar sudo newgrp docker ou fazer logout/login para aplicar as alterações.
Se preferir não alterar já os grupos do sistema, pode simplesmente executar os comandos deste lab com sudo, tal como já aparecem nos blocos executados no host.
Confirme antes de prosseguir:
docker versionSe este comando falhar e também não tiver como obter acesso ao grupo docker, pare aqui e resolva primeiro o acesso ao daemon Docker.
2. Obter a Imagem do IBM MQ
Basta executar o comando:
docker pull icr.io/ibm-messaging/mq:latest1. Criar os Ficheiros de Configuração
MQ Nodes (.ini)
Vamos criar três ficheiros de configuração distintos para cada nó.
Crie o ficheiro para o 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)
EOFCrie o ficheiro para o 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)
EOFCrie o ficheiro para o 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)
EOFFicheiro de Configuração MQ (config.mqsc)
Crie o ficheiro com toda a configuração de segurança e fila. O IBM MQ Docker image executa automaticamente ficheiros .mqsc montados em /etc/mqm/ no arranque do nó ativo — os réplicas recebem a mesma configuração por replicação 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. O Ficheiro de Orquestração (Cluster + Cliente)
Recrie o ficheiro:
rm -f docker-compose.yamlDepois, abra o ficheiro:
vi docker-compose.yamlE cole exatamente este conteúdo:
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 o Cluster
Inicie os contentores:
docker compose down -v
docker compose up -dAguarde alguns segundos e confirme que o cluster está estável e que o ficheiro config.mqsc foi 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; doneO esperado é observar um nó com ROLE(Active) e os outros dois com ROLE(Replica). Se os contentores ainda estiverem a inicializar, aguarde mais alguns segundos e repita.
Identifique o nó ativo e confirme que a fila e o canal foram criados automaticamente pelo 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. Teste de Quorum e Replicação Síncrona
Nesta primeira fase, vamos provar que o cluster sobrevive e mantém os dados consistentes internamente.
Passo 1: Colocar Mensagem no Líder
Identifique qual o nó ativo e guarde-o numa variável:
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"Depois, coloque uma mensagem nesse nó:
docker exec -it "$ACTIVE_NODE" /opt/mqm/samp/bin/amqsput HA.TEST.QUEUE QM_HAEscreva: "Validando replicação síncrona" e pressione Enter duas vezes.
Passo 2: Simular Falha (Stop Container)
Pare o contentor que está ativo:
docker stop "$ACTIVE_NODE"Passo 3: Verificar Eleição e Consistência
Verifique quem é o novo líder e guarde-o numa variável:
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 aí a mensagem:
docker exec -it "$NEW_ACTIVE_NODE" /opt/mqm/samp/bin/amqsget HA.TEST.QUEUE QM_HAO sucesso prova que a mensagem foi replicada para o log local do novo líder antes da queda do nó originalmente ativo.
5. Demonstração de ACR (Automatic Client Reconnect)
Agora que validámos o backend, vamos testar a resiliência do lado da aplicação com o sample amqsphac, que usa MQCNO_RECONNECT internamente e mantém o loop de envio ativo durante e após o failover.
Passo 1: Garantir que o cluster está operacional
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"Passo 2: Criar o script de arranque do sample
Escreva o script linha a linha para evitar problemas com a colagem de comandos multi-linha:
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'Passo 3: Iniciar o sample em background
docker exec -d mq-client bash -c '/tmp/acr.sh'O amqsphac não produz output linha a linha em modo não-interativo (buffering de stdout), por isso a verificação é feita pela profundidade da fila. Confirme que as mensagens estão a chegar ao nó ativo:
sleep 5 && docker exec "$ACTIVE_NODE" bash -lc 'echo "DISPLAY QLOCAL(HA.TEST.QUEUE) CURDEPTH" | runmqsc QM_HA'O CURDEPTH deve estar a crescer continuamente.
Passo 4: Provocar a falha do nó ativo
docker stop "$ACTIVE_NODE"Passo 5: Verificar a eleição do novo 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"Passo 6: Confirmar a reconexão automática pelo crescimento da fila
Aguarde cerca de 10 segundos para a eleição completar e verifique o CURDEPTH no novo líder:
sleep 10 && docker exec "$NEW_ACTIVE_NODE" bash -lc 'echo "DISPLAY QLOCAL(HA.TEST.QUEUE) CURDEPTH" | runmqsc QM_HA'Se o CURDEPTH estiver a crescer no novo líder, o amqsphac reconectou automaticamente sem qualquer intervenção — o ACR funcionou.
Passo 7: Confirmar as mensagens recebidas
docker exec -it "$NEW_ACTIVE_NODE" /opt/mqm/samp/bin/amqsget HA.TEST.QUEUE QM_HAPrincipais Conclusões para Docker
- Resiliência em Camadas: Validámos primeiro a replicação de dados e depois a continuidade da aplicação.
- ACR & Native HA: A combinação perfeita para arquiteturas de alta disponibilidade total. O
amqsphacusaMQCNO_RECONNECTpara demonstrar a reconexão transparente que uma aplicação real deve implementar. - Configuração Robusta: O uso de volumes para montar as stanzas de configuração do Native HA é a abordagem mais fiável.
Cleanup
No fim do lab, pode remover os contentores e os ficheiros criados durante a experiência:
docker compose down -v
rm -f node1.ini node2.ini node3.ini config.mqsc docker-compose.yamlEste cleanup não desinstala Docker, Docker Compose ou a imagem do IBM MQ. Remove apenas os artefactos locais usados neste lab.