Search code examples
javaspring-bootibm-mq

How to connect to an IBM MQ uniform cluster


I recently posted this How to reconnect to all IBM MQ queue managers in a cluster question and I was suggested that a uniform cluster would be the solution. Reading through the docs it seemed to be exactly what we need.

Our infrastructure guys configured the uniform cluster and I am trying to connect to it and test the functionality.

To connect to that I created a json CCDT file similar with below:

{
  "channel":
  [
    {
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server1",
            "port": 1414
          }
        ],
        "queueManager": "QM1"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server2",
            "port": 1414
          }
        ],
        "queueManager": "QM2"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server3",
            "port": 1414
          }
        ],
        "queueManager": "QM3"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server1",
            "port": 1414
          },
          {
          "host": "server2",
          "port": 1414
          },
          {
          "host": "server3",
          "port": 1414
          }
        ],
        "queueManager": "*"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    }
  ]
}

In other words I was trying to create a client connection to each queue manager and a forth one to the group of three queue managers. Initially this entry was not in the file "queueManager": "*" but when trying to run I was getting missing required attribute. That made me put that " * ". The error went away however I am still unable to connect which make me think that my CCDT config is wrong. On the client side I have this ConnectionFactory creation:

        connectionFactory.setTransportType(WMQ_CM_CLIENT);
        if (Objects.isNull(ccdtUrl)) {
            connectionFactory.setConnectionNameList(connectionNameList);
            connectionFactory.setChannel(queueManagerChannel);
            connectionFactory.setPort(connectionPort);
        } else {
            connectionFactory.setCCDTURL(ccdtUrl);
        }
        connectionFactory.setCCSID(1208);
        connectionFactory.setClientReconnectOptions(WMQ_CLIENT_RECONNECT_Q_MGR);
        connectionFactory.setClientReconnectTimeout(reconnectTimeout);
        connectionFactory.setAppName(applicationName);

        if (sslEnabled) {
            connectionFactory.setSSLCipherSuite(sslCipherSuite);
            connectionFactory.setSSLFipsRequired(sslFipsRequired);
            System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", useIBMCipherMappings);
        }

Can you advise about what I am doing wrong and how can I fix it. I haven't used CCDT before.

Thank you in advance.

UPDATE

Following the provided answer and the comments I ended up with this CCDT definition:

{
  "channel":
  [
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server1",
            "port": 1415
          }
        ],
        "queueManager": "QM1"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server2",
            "port": 1415
          }
        ],
        "queueManager": "QM2"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server3",
            "port": 1415
          }
        ],
        "queueManager": "QM3"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server1",
            "port": 1415
          }
        ],
        "queueManager": "QMGROUP"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server2",
            "port": 1415
          }
        ],
        "queueManager": "QMGROUP"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    },
    {
      "connectionManagement":
      {
        "clientWeight": 10,
        "affinity": "none"
      },
      "general":
      {
        "description": "My channel",
        "maximumMessageLength": 4194304
      },
      "name": "CHANNEL.NAME",
      "clientConnection":
      {
        "connection":
        [
          {
            "host": "server3",
            "port": 1415
          }
        ],
        "queueManager": "QMGROUP"
      },
      "transmissionSecurity":
      {
        "cipherSpecification": "TLS_AES_256_GCM_SHA384"
      },
      "type": "clientConnection"
    }
  ]
}

And this connection factory implementation on the client side:

        connectionFactory.setTransportType(WMQ_CM_CLIENT);
        if (Objects.isNull(ccdtUrl)) {
            connectionFactory.setConnectionNameList(connectionNameList);
            connectionFactory.setChannel(queueManagerChannel);
            connectionFactory.setPort(connectionPort);
            if (sslEnabled) {
                connectionFactory.setSSLCipherSuite(sslCipherSuite);
                connectionFactory.setSSLFipsRequired(sslFipsRequired);
                System.setProperty("com.ibm.mq.cfg.useIBMCipherMappings", useIBMCipherMappings);
            }
        } else {
            connectionFactory.setCCDTURL(ccdtUrl);
            connectionFactory.setQueueManager("*QMGROUP");
        }
        connectionFactory.setCCSID(1208);
        connectionFactory.setClientReconnectOptions(WMQ_CLIENT_RECONNECT);
        connectionFactory.setClientReconnectTimeout(reconnectTimeout);
        connectionFactory.setAppName(applicationName);

When deployed we were able to process a message, then we started seeing lots of connection broken exceptions, the service became unhealthy and being restarted.

Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').

At this point I am not sure if this was caused by my CCDT configuration and or the way I created connection factory or by the way the cluster was configured. We know that the cluster works OK when the connection factory is not driven by CCDT.

Any advice much appreciated.


Solution

  • You need to have a CCDT with n x 2 entries.

    • 1 entry for each individual queue manager with the queue manager name set to the REAL queue manager name (as you have)
    • 1 entry for each individual queue manager with the queue manager name set to the group name - anything you want, I tend to use the Uniform Cluster name.

    So just duplicate the first three entries, and then edit the queue manager names.

    Also, in your client program, do not set any channel attributes, e.g. channel name, connection name, port number, ssl cipher, as those attributes all come from the CCDT. That looks like what you are doing, but I thought I'd mention it explicitly as I'm not sure where your sslEnabled boolean is coming from.

    Ensure your reconnect options are not limited to the queue manager, but allow the connection to be sent to another queue manager, so use WMQ_CLIENT_RECONNECT rather than WMQ_CLIENT_RECONNECT_Q_MGR.

    And as @JoshMc said in his comment, ensure your connect is made using a queue manager name of the group name, whatever it was you chose.

    For further reading, this blog post released by Hursley, at the time JMS was supported by Application Rebalancing, might be of interest.