Article

A deep dive into client channel definition tables (CCDTs) in IBM MQ uniform clusters

Understand what a CCDT is and how they are used in IBM MQ uniform clusters

By

Simone Jain

To carry out any form of messaging, applications need to be able to interact with queues; and, to do that, they need to connect to queue managers. The client channel definition table, or CCDT, provides client applications with the information that they need to connect to a queue manager. The CCDT is particularly useful for applications that need to connect to a number of alternative queue managers, such as when they are connected to a uniform cluster.

In this article, we’ll explain what a CCDT is and how to set one up. Also, we’ll explore the role that CCDTs play in messaging applications and specific considerations we need to make when using them in a uniform cluster setting.


Video will open in new tab or window.

What is a client channel definition table (CCDT)?

A CCDT is essentially an address book, containing several channel definitions. Every time a new queue manager is defined, a corresponding channel definition must be added to the CCDT. While CCDTs might seem daunting, they have a very simple structure. This means that after you’ve created one channel definition, you can often duplicate it with basic modifications for each new queue manager you define.

A minimal channel definition would be comprised of:

  • Channel name
  • Connection information (host name and port number)
  • Queue manager name
  • Connection type (all connection types in a CCDT should be clientConnection)

For the majority of use cases, specifying only these channel attributes is sufficient, but the full list of channel attributes that are supported by JSON-formatted CCDTs can be found in the IBM MQ docs.

By using a JSON-formatted CCDT, you can eliminate forward and backward compatibility issues with differing versions of IBM MQ for the client application, queue manager, and CCDT itself. The only thing to note is that if the client application is using an older version of IBM MQ and the CCDT makes use of channel attributes introduced in a newer version, the client application will ignore these attributes.

With this basic information, a client application has everything it needs to connect to the queue manager over TCP/IP. While TCP/IP is the default protocol for CCDTs defined in JSON, you can specify protocols other than TCP/IP in the binary-format CCDT (which you can read more about in the IBM MQ docs).

Now that we know why we need CCDTs, let’s look at an example of a basic CCDT, which contains just one channel definition:

{
  "channel": [
    {
      "name": "DEV.APP.SVRCONN",
      "clientConnection": {
        "connection": [
          {
            "host": "localhost",
            "port": 1415
          }
        ],
        "queueManager": "QM1"
      },
      "type": "clientConnection"
    }
  ]
}

This channel definition provides a client application with all the information it needs to establish a client connection to QM1. The client application needs to connect to host localhost at port 1415 using the TCP/IP protocol. If no port is specified, the default 1414 is used. The type of connection created between the client application and the queue manager is clientConnection, and as mentioned earlier, all channel definitions in a CCDT should be of this type. The name assigned to this clientConnection is DEV.APP.SVRCONN and there will be a corresponding server connection of the same name from the queue manager. You can find this simple client connection example, along with other examples, in the IBM MQ docs. You can also use this JSON schema to validate your CCDT.

A CCDT needs to be located where all client applications that need to use it have access to the latest version. For instructions on how to specify the location of the CCDT, see the IBM MQ docs.

CCDTs and uniform clustering

As mentioned earlier, CCDTs are particularly useful for applications connecting to uniform clusters. These applications must be in client mode, which means that they don’t have to be on the same system as a queue manager to connect to it, and therefore won’t have an affinity with it. This configuration is necessary in a uniform cluster setting to allow the application to reconnect to any queue manager for balancing.

To take advantage of this feature, connecting applications need to be able to access the connection information for all cluster members. That’s where the CCDT comes in. By populating a CCDT with channel definitions for all of the queue managers in a uniform cluster, client applications will have all the information they need to reconnect to the queue managers they get rebalanced to.

If an application specified that it wants to connect to QM1 and does this using a CCDT which only contained channel definitions for the individual queue managers in the uniform cluster, it would be able to do so provided that QM1 is available. If QM1 became temporarily unavailable, the application would not be able to connect to it or any other queue manager in the uniform cluster. To prevent this, we need a way to ensure the application can initially connect to the uniform cluster without being dependant on any particular queue manager.

We need to define a single client connection that contains the connection information of all the queue managers in the uniform cluster. The application then simply needs to specify that it wants to use this list, which will ensure it connects to any available queue manager in that uniform cluster. This is called a connection list.

The process of an application connecting to a uniform cluster is as follows:

  1. The application sets its QMGR attribute to the queue manager name in the connection list.
  2. The application looks in its CCDT for the client connection with the corresponding value of queueManager (for example, “queueManager”: “ANY_QM”).
  3. The application attempts to connect to each queue manager in the list, starting from the top, until it makes a successful connection.

As mentioned earlier, once it has successfully connected to one queue manager using this list, it is definitely in the right uniform cluster so will only be asked to reconnect to queue managers in it.

Once in the uniform cluster, rebalancing is negotiated as follows:

  1. The application will be provided with the name of a specific queue manager to reconnect to.
  2. The application looks in its CCDT for the connection information corresponding to the queue manager name it’s been given and, if found, will reconnect to that queue manager.

The following animation illustrates this whole process. Don’t worry about the values that are set for specific attributes yet - these attributes are covered in depth later in the article.

alt

Let’s now see what this looks like in a CCDT.

Imagine that you have a uniform cluster that is comprised of three queue managers (QM1, QM2, QM3) that connect to localhost at ports 1411, 1412, and 1413 respectively. The CCDT for this uniform cluster would look like this (found here):

{
    "channel": [{
        "name": "DEV.APP.SVRCONN",
        "clientConnection": {
          "connection": [{
            "host": "localhost",
            "port": 1411
           },{
            "host": "localhost",
            "port": 1412
           },{
            "host": "localhost",
            "port": 1413
            }],
          "queueManager": "ANY_QM"
        },
        "type": "clientConnection"
        },
        {
            "name": "DEV.APP.SVRCONN",
            "clientConnection":
            {
                "connection":
                [
                    {
                        "host": "localhost",
                        "port": 1411
                    }
                ],
                "queueManager": "QM1"
            },
            "type": "clientConnection"
        },
        {
            "name": "DEV.APP.SVRCONN",
            "clientConnection":
            {
                "connection":
                [
                    {
                        "host": "localhost",
                        "port": 1412
                    }
                ],
                "queueManager": "QM2"
            },
            "type": "clientConnection"
        },
        {
            "name": "DEV.APP.SVRCONN",
            "clientConnection":
            {
                "connection":
                [
                    {
                        "host": "localhost",
                        "port": 1413
                    }
                ],
                "queueManager": "QM3"
            },
            "type": "clientConnection"
        }
   ]
}

Except for the first one, we have three standard channel definitions for our three queue managers. The first channel definition uses a connection list, so let’s look at that more closely:

"name": "DEV.APP.SVRCONN",
        "clientConnection": {
          "connection": [{
            "host": "localhost",
            "port": 1411
           },{
            "host": "localhost",
            "port": 1412
           },{
            "host": "localhost",
            "port": 1413
            }],
          "queueManager": "ANY_QM"

The queue manager name in this list is ANY_QM and it specifies three connections for each of the queue managers in the uniform cluster. We could have set the queue manager name to be anything, and it would work in the same way; ANY_QM was chosen for readability. All queue managers in this list belong to the same uniform cluster, so once a client has connected to one of these, we can guarantee it is in the correct uniform cluster.

The client application will specify ANY_QM as the queue manager it wants to connect to and begin connection attempts from the first entry in the list, until it is able to connect to a queue manager.

Now that the application is in the uniform cluster, we can just give it the name of any queue manager in the uniform cluster, and it should just connect, right? Not quite. Remember that to connect to the uniform cluster we set the queue manager name in the application to ANY_QM, which means it can only connect to queue managers of that name. This works well to initially bring the application to the correct uniform cluster, but once it’s in, it will be given specific queue manager names to reconnect to (in our example, QM1, QM2, or QM3) since the uniform cluster has no knowledge of ANY_QM. This was simply a list we created to identify queue managers belonging to a single uniform cluster. Once it is in, we want the application to be able to connect to any of the queue managers when given their actual name. To do this, we need to set the queue manager name to *ANY_QM in the client application. The * acts as a wildcard and says that the app shouldn’t be too concerned with the actual queue manager name, as long as its connection information can be found in the ANY_QM connection list.

You may be wondering: why do we need the other three channel definitions if the first one has all the information you need to connect to any queue manager in the uniform cluster? The point is, that first channel definition does contain the information to connect to any queue manager. In a uniform cluster, applications will be told to go to a specific queue manager, so we need to have channel definitions based on the specific names of each queue manager. For example, your application might enter the uniform cluster by connecting to QM3 (having specified ANY_QM), and later be asked to connect to QM1. If we only had the first channel definition, the application would look in its CCDT for a queue manager named QM1 and be unable to reconnect because there isn’t a queue manager of that name in the CCDT. Having the specific definitions means that it can connect to a specific queue manager by name once in the uniform cluster.

It’s important to note that no extra developer intervention is needed for application rebalancing – the MQ client libraries used by your application take over responsibility for connecting to queue managers and the process is invisible to your application.

With this CCDT, your application can reliably be reconnected to any queue manager in a uniform cluster - provided you do these key things:

  • Specify a connection list that contains the connection information for all the queue managers in the uniform cluster.
  • Set the value of the QMGR attribute in your client application to the queue manager name in this connection list.
  • Define specific channel definitions for each queue manager in the uniform cluster.

Summary and next steps

The CCDT might seem complicated at first, but it really is just an address book that provides your client application with the information it needs to connect to a queue manager. For uniform clusters, the CCDT must use a connection list. This connection list makes sure that your client application enters the correct uniform cluster initially and will only be asked to reconnect to members of this cluster.

Now that you know how to create a CCDT, get hands-on and set up a uniform cluster of your own with this tutorial, "Setting up a uniform cluster in IBM MQ."