← Back to list

IBM MQ

An IBM MQ server hosts one or more queue managers that provide messaging services to applications.

DevNotes · 2026-03-02 07:39 · 0 claps · 9.7 min read
#ibm-mq-uniform-cluster #ibm-mq-cluster #ibm-mq
Open on Medium ↗

IBM MQ

An IBM MQ server hosts one or more queue managers that provide messaging services to applications.

A queue manager is responsible for:

  • Storing messages in queues
  • Routing messages to other queue managers
  • Managing MQ objects (queues, channels, listeners, etc.)
  • Handling communication with applications (Java programs or other MQ clients).

All MQ objects (such as queues and channels) exist on the queue manager, not on the client. The client only connects to the queue manager to access these objects. A quiet queue manager is a queue manager that is running but not accepting new application connections or work.

An IBM MQ client is a component that allows an application running on a separate system to connect to a remote queue manager.

The MQ client:

  • Enables the application to issue MQI calls (such as MQPUT and MQGET)
  • Sends these calls to the queue manager over the network
  • Receives responses from the queue manager and passes them back to the application

The client itself does not store messages, all message storage and processing happen on the queue manager.

Queues in IBM MQ

Queues are data structures managed by a queue manager and are used to store messages until they are processed by an application.

A dynamic queue is created automatically by the queue manager when requested by an application. It is created based on a model queue. It can be: → Temporary (non-persistent) — deleted when the application disconnects. → Permanent (persistent dynamic queue) — remains until explicitly deleted. Dynamic queues are commonly used for reply-to patterns.

A local queue is a queue that physically resides on the queue manager where it is defined. Messages are stored on this queue until consumed by an application.

A Transmission Queue (XMITQ) is a special type of local queue created by an administrator. It is used to temporarily store messages that are destined for a remote queue manager. When an application puts a message to a remote queue, the message is placed on the transmission queue, aSender Channel reads messages from the transmission queue and the channel sends the message to the remote queue manager.

An Initiation Queue is a local queue used for triggering. When a triggering condition occurs (for example, a message arrives on a queue), the queue manager places a trigger message on the initiation queue. This trigger message starts a program to process messages. A trigger event is an event that causes an application to start processing a queue.

A Dead Letter Queue (DLQ) is a special local queue defined on a queue manager. The queue manager places messages on the DLQ when it cannot deliver them to their intended queue, for example, when the target queue does not exist, queue is full or authorization failure.

IBM MQ provides system queues such as:

  • System Command Queue — used for administrative commands.
  • System Default Queues — templates used when creating new queues.
  • Event Queues — used to report system and application events. When you define a new local queue, it inherits default properties from a system default local queue.

A Remote Queue is a definition on a local queue manager that represents a queue located on another queue manager. It does not store messages and it contains routing information (remote queue name, remote queue manager name, transmission queue). When an application puts a message to a remote queue definition, the message is routed to the appropriate transmission queue.

A Model Queue is a template used to create dynamic queues. Applications request the creation of dynamic queues based on a model queue’s attributes.

An Alias Queue is an alternative name for an existing queue. It allows applications to use different queue names and redirection of applications without changing application code. Multiple applications can access the same underlying queue using different alias names.

Channels in IBM MQ

For queue managers to communicate with each other, you must define channels. A channel is a logical communication link used to transfer data between:

  • Two queue managers
  • An MQ client and a queue manager
  • An AMQP client and a queue manager

Channel Types

Message Channels (Queue Manager to Queue Manager) are used to transfer messages between queue managers. They are unidirectional. Common types:

  • Sender (SDR) — sends messages
  • Receiver (RCVR) — receives messages
  • **Cluster Sender (CLUSSDR)
  • Cluster Receiver (CLUSRCVR)**

For communication between two queue managers, we must define one channel at each end of the connection:

  • A Sender (SDR) channel on the source queue manager
  • A Receiver (RCVR) channel on the destination queue manager Together, they form a channel pair.

If the remote queue manager needs to send messages back, you must define another channel pair in the opposite direction. So for two-way message flow, you need:

  • One sender and receiver pair from QM1 → QM2
  • Another sender and receiver pair from QM2 → QM1

MQI Channels (Client Channels) connect an MQ client application to a queue manager. They are bidirectional. Types:

  • Server-connection (SVRCONN) — defined on the queue manager
  • Client-connection (CLNTCONN) — defined on the client side These channels transfer MQI calls (MQPUT, MQGET, etc.) and return responses from the queue manager to the client

IBM MQ Clusters

An IBM MQ cluster allows multiple queue managers (QMs) to work together and share queue definitions without manually defining remote queues and transmission queues.

Repositories in a Cluster

Each queue manager in a cluster maintains cluster information in special SYSTEM.CLUSTER.* queues (not just one system queue).There are two types of repositories:

Full Repository (FR) contains information about all queue managers and cluster queues in the cluster and acts as a central reference point. You must have at least one full repository, but best practice is to have two for high availability.

Partial Repository (PR) contains information only about itself, the cluster queues it hosts, the cluster queues it needs to access. Partial repositories automatically retrieve cluster information from full repositories.

Cluster Channels To join a cluster, a queue manager must define:

  • A Cluster Receiver (CLUSRCVR) channel
  • At least one Cluster Sender (CLUSSDR) channel to a full repository

Example: QM1 and QM4 = Full Repositories QM2 and QM3 = Partial Repositories

On QM2 and QM3, you manually define:

  • One CLUSRCVR channel
  • One CLUSSDR channel pointing to a full repository (e.g., QM1)

On QM1, you define its own CLUSRCVR channel.

Channels are not automatically created. They must be manually defined (at least the initial cluster channels).

A cluster queue is a local queue that is shared with the cluster. Once defined, other queue managers in the cluster can send messages to it. No need to manually define remote queues.

Any application connected to any queue manager in the cluster can PUT messages to a cluster queue (from anywhere) and GET messages only if it connects to the queue manager where that queue physically resides.

If an application connected to QM1 wants to send a message to a queue hosted on QM2, the queue must be defined as a cluster queue on QM2, messages are routed using cluster channels and transmission queues are managed automatically (SYSTEM.CLUSTER.TRANSMIT.QUEUE). You do NOT manually create remote queue definitions, transmission queues or sender channels between every pair. Cluster handles that automatically after initial setup.

Important: Client Connections SVRCONN channels are used for client applications to connect to a queue manager. They are NOT used between queue managers.

IBM MQ Uniform Clusters

A Uniform Cluster is a feature introduced to simplify workload balancing across multiple queue managers in a cluster.

It is mainly used for stateless applications where you want automatic load balancing, even distribution of client connections, easier horizontal scaling.

In a normal MQ cluster:

  • You define a cluster queue on multiple QMs.
  • Clients must manually connect to a specific QM.
  • Load balancing is basic (round-robin for puts).
  • Client connections are not automatically balanced. Uniform clusters improve this.

A uniform cluster queue is a queue with the same name defined on multiple queue managers in a cluster. All QMs host the same queue name. The cluster automatically balances message puts. Applications can connect to any QM.

In a uniform cluster, client connections are balanced across QMs(using a CCDT (Client Channel Definition Table)), if one QM goes down, clients reconnect to another and no manual routing logic needed.

For the following section, I used Claude Code to help me set up a uniform cluster containing two Queue Managers and each with one cluster queue. This setup can be used to spin up the IBM MQ server in a non-prod environment and play around with it to familiarize yourself with a Uniform Cluster.

/ibmmq-config/Dockerfile

FROM --platform=linux/amd64 icr.io/ibm-messaging/mq:latest

COPY --chown=mqm uniclus.ini /etc/mqm/uniclus.ini

COPY --chmod=755 entrypoint-wrapper.sh /usr/local/bin/entrypoint-wrapper.sh

ENTRYPOINT ["/usr/local/bin/entrypoint-wrapper.sh"]

/ibmmq-config/entrypoint-wrapper.sh

#!/bin/bash
set -e

# Reads the queue manager name from the Docker env var (e.g. QM1 or QM2).
QM_NAME="${MQ_QMGR_NAME}"

# Converts it to lowercase (e.g. qm1) — needed for the Docker network hostname in CONNAME.
QM_LOWER=$(echo "$QM_NAME" | tr '[:upper:]' '[:lower:]')

# Builds the CLUSRCVR channel name, e.g. UNICLUSTER_QM1.
CHANNEL_NAME="UNICLUSTER_${QM_NAME}"

# Creates an MQSC script file dynamically with the QM's own name injected. This file is picked up automatically by runmqdevserver on startup.
cat > /etc/mqm/uniclus.mqsc << EOF
* Creates the inbound cluster receiver channel for this QM. CONNAME uses the Docker hostname (e.g. qm1(1414))
DEFINE CHANNEL('${CHANNEL_NAME}') CHLTYPE(CLUSRCVR) TRPTYPE(TCP) CONNAME('${QM_LOWER}(1414)') REPLACE

* Assigns it to the cluster. Done as a separate ALTER because DEFINE + CLUSTER together caused issues
ALTER CHANNEL('${CHANNEL_NAME}') CHLTYPE(CLUSRCVR) CLUSTER(UNICLUSTER)

* Creates the shared queue, advertised to the cluster. DEFBIND(NOTFIXED) allows routing to any QM; CLWLUSEQ(ANY) enables workload balancing at queue level
DEFINE QLOCAL(ORDERS.Q) CLUSTER(UNICLUSTER) DEFBIND(NOTFIXED) CLWLUSEQ(ANY) MAXDEPTH(500) REPLACE
ALTER QMGR CLWLUSEQ(ANY)

* Removes any existing CHLAUTH rule that might block the app channel
SET CHLAUTH('DEV.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') ACTION(REMOVE)

* Allows connections on the app channel using the channel's own user context
SET CHLAUTH('DEV.APP.SVRCONN') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(CHANNEL) CHCKCLNT(ASQMGR) ACTION(ADD)

* Disables connection authentication (no password required)
ALTER QMGR CONNAUTH('')

* Applies the security change immediately
REFRESH SECURITY TYPE(CONNAUTH)

* Allows inter-QM cluster channels to connect as mqm. Without this, the default deny-all rule blocks CLUSRCVR
SET CHLAUTH('UNICLUSTER_*') TYPE(ADDRESSMAP) ADDRESS('*') USERSRC(MAP) MCAUSER('mqm') ACTION(ADD)
EOF

# Starts the MQ server in the background and saves its PID so the script can wait for it later.
/usr/local/bin/runmqdevserver &
BGPID=$!

# Polls dspmq every 2 seconds until the QM reports Running. Needed because the CLUSSDR setup and setmqaut below must run after the QM is fully up.
echo "Waiting for queue manager ${QM_NAME} to start..."
until dspmq -m "${QM_NAME}" 2>/dev/null | grep -q "Running"; do
  sleep 2
done
echo "Queue manager ${QM_NAME} is running"

# Grants the app user put/get/browse/inquire access to ORDERS.Q. Uses setmqaut (not SET AUTHREC in MQSC) because MQSC uppercases principal names, breaking the lowercase app user.
setmqaut -m "${QM_NAME}" -t queue -n ORDERS.Q -p app +put +get +browse +inq
echo "Granted app access to ORDERS.Q"

# Determines which QM is the partner — each QM points its CLUSSDR at the other one.
if [ "${QM_NAME}" = "QM1" ]; then
  PARTNER_NAME="QM2"; PARTNER_HOST="qm2"
else
  PARTNER_NAME="QM1"; PARTNER_HOST="qm1"
fi
CLUSSDR_NAME="UNICLUSTER_${PARTNER_NAME}"
echo "DEFINE CHANNEL('${CLUSSDR_NAME}') CHLTYPE(CLUSSDR) TRPTYPE(TCP) CONNAME('${PARTNER_HOST}(1414)') CLUSTER(UNICLUSTER) REPLACE
START CHANNEL(${CLUSSDR_NAME})" | runmqsc "${QM_NAME}" || true
echo "Started CLUSSDR ${CLUSSDR_NAME} -> ${PARTNER_HOST}(1414)"

# Waits for the background runmqdevserver process. This keeps the container running as long as MQ is running.
wait $BGPID

/ibmmq-config/uniclus.ini

AutoCluster:
    Type=Uniform
    ClusterName=UNICLUSTER
    Repository1Name=QM1
    Repository1Conname=qm1(1414)
    Repository2Name=QM2
    Repository2Conname=qm2(1414)

Commands for building the Docker image for the IBM MQ server and starting containers for two queue managers in a Uniform Cluster:

# Move to the root ibm config folder
cd /ibmmq-config

docker network create mqnetwork

docker rm -f qm1 qm2
docker volume rm qm1data qm2data

docker build --no-cache --platform linux/amd64 -t mq-unicluster . 

docker run -d --name qm1 --network mqnetwork --platform=linux/amd64 -e LICENSE=accept -e MQ_QMGR_NAME=QM1 -e MQ_ADMIN_PASSWORD=passw0rd -e MQ_APP_PASSWORD=passw0rd -e CONNAME="qm1(1414)" -v qm1data:/mnt/mqm -p 1414:1414 -p 9443:9443 mq-unicluster
docker run -d --name qm2 --network mqnetwork --platform=linux/amd64 -e LICENSE=accept -e MQ_QMGR_NAME=QM2 -e MQ_ADMIN_PASSWORD=passw0rd -e MQ_APP_PASSWORD=passw0rd -e CONNAME="qm2(1415)" -v qm2data:/mnt/mqm -p 1415:1414 -p 9444:9443 mq-unicluster

docker exec -it qm1 dspmq
runmqsc QM1
DISPLAY CLUSQMGR(*)

docker exec qm1 bash -c "echo 'DISPLAY CLUSQMGR(*) ALL' | runmqsc QM1"
docker exec qm1 bash -c "echo 'DISPLAY CHANNEL(UNICLUSTER_QM1) CLUSTER CONNAME' | runmqsc QM1"

docker logs qm1 --tail 50
docker exec qm1 bash -c "dspmq -m qm1"

I also started a spring boot application that was sending and consumming messages to the Uniform Cluster, using the following configuration:

# One instance was started with this config:
spring:
  ibm:
    mq:
      connName: "localhost(1414),localhost(1415)"
      channel: DEV.APP.SVRCONN

# The second instance was started with this config:
spring:
  ibm:
    mq:
      connName: "localhost(1415),localhost(1414)"
      channel: DEV.APP.SVRCONN

# The reason for switching the hosts in the connName list 
# is because the com.ibm.mq:com.ibm.mq.jakarta.client:9.4.1.0 
# always tries connecting to the first host specified in the connName list
# and both spring boot instances would end up connecting to 
# the same queue manager.

# This way, each spring boot instance connects to different queue manager
# if the queue managers are up and running.

The scenarios tested so far:

  1. Given both QMs and both spring boot apps up and running, when sending messages to any of app instances, then the messages are equally distributed across both QMs and each app instance consumes messages from its corresponding QM.
  2. Using the setup from the first scenario, when stopping QM1 and sending messages to any of the app instances, then the messages are routed only to QM2 (as the first spring boot instance switched from QM1 to QM2 automatically) and both app instances consume unique messages from QM2 only.
  3. Using the setup from the second scenario, when restarting QM1 and sending messages to any of the app instances, then the messages are equally distributed across both QMs but the app instances keep on consuming messages from QM2 only. So the consumer connections are not rebalanced automatically.

IBM MQ COMMANDS

https://www.ibm.com/docs/en/ibm-mq/9.4.x?topic=reference-command-sets-comparison

# Set a Queue Manager as Full Repository
ALTER QMGR REPOS(IBM_MQ_CLUSTER)

# Set a Queue Manager as Partial Repository. 
# Empty REPOS removes full repository role
ALTER QMGR REPOS('')

------------------------------------------------------------------------------

# Cluster Receiver Channel (defined on QM1)
DEFINE CHANNEL(TO.QMGR1) CHLTYPE(CLUSRCVR) +
       TRPTYPE(TCP) +
       CONNAME('localhost(1414)') +
       CLUSTER(IBM_MQ_CLUSTER)

# Cluster Sender Channel (defined on QM2, pointing to QM1)
# CLUSSDR must point to a CLUSRCVR channel on the full repository
# Channel names must match
DEFINE CHANNEL(TO.QMGR1) CHLTYPE(CLUSSDR) +
       TRPTYPE(TCP) +
       CONNAME('localhost(1414)') +
       CLUSTER(IBM_MQ_CLUSTER)

# Define a Cluster Queue (on QM1)
DEFINE QLOCAL(APP_A.QUEUE) CLUSTER(IBM_MQ_CLUSTER)

------------------------------------------------------------------------------

# Create a Queue Manager
crtmqm QMGR1

# Start a Queue Manager
strmqm QMGR1

# Display Queue Manager Status
dspmq

# Enter MQSC Interface
runmqsc QMGR1

------------------------------------------------------------------------------

# Display Objects
DISPLAY QUEUE(*)
DISPLAY CHANNEL(*)
DISPLAY QMGR

# Disable Channel Authentication (usually for testing only)
ALTER QMGR CHLAUTH(DISABLED)

# Create a Local Queue
DEFINE QLOCAL(QMGR1_LQ)

# Display Local Queue
DISPLAY QLOCAL(QMGR1_LQ)

# Disable PUT on Queue
ALTER QLOCAL(QMGR1_LQ) PUT(DISABLED)

# Create Transmission Queue
DEFINE QLOCAL(XMITQ_QMGR1) USAGE(XMITQ)

# Display Queue Manager Details
DISPLAY QMGR
DIS QMGR

# Create Dead Letter Queue
DEFINE QLOCAL(DEAD.LETTER.QUEUE)

# Associate DLQ with Queue Manager
ALTER QMGR DEADQ(DEAD.LETTER.QUEUE)

# Display All SYSTEM Queues
DISPLAY QLOCAL(SYSTEM.*)

# Define Remote Queue
# (You must specify RNAME, RQMNAME and XMITQ)
DEFINE QREMOTE(QMGR1_RQ) +
       RNAME(TARGET_QUEUE) +
       RQMNAME(QMGR2) +
       XMITQ(XMITQ_QMGR2)

# Display Remote Queue
DISPLAY QREMOTE(QMGR1_RQ)

# Define Alias Queue
DEFINE QALIAS(QMGR1_QA) TARGET(QMGR1_LQ)

# Define Model Queue
DEFINE QMODEL(QMGR1_MODEL)

------------------------------------------------------------------------------

# Display Listeners
DISPLAY LISTENER(*)

# Display Default TCP Listener
DISPLAY LISTENER(SYSTEM.DEFAULT.LISTENER.TCP)

# Define Listener
DEFINE LISTENER(QMGR1_LSR) TRPTYPE(TCP) PORT(1414)

# Start Listener
START LISTENER(QMGR1_LSR)

# Display Listener Status
DISPLAY LSSTATUS(*)

메타데이터
post_id
b75771eaba82
slug
ibm-mq-b75771eaba82
url
https://medium.com/@devnotes/ibm-mq-b75771eaba82
canonical_url
https://medium.com/@devnotes/ibm-mq-b75771eaba82
author_url
https://medium.com/@devnotes
status
ok
fetched_at
2026-06-09 15:37:30