Search This Blog

Wednesday, January 13, 2016

Using Channel compression in WebSphere MQ

Preface

Starting with WebSphere MQ v6.1 IBM introduced the channel compression for the data that flows between queue managers. This is a good feature that makes optimum use of the network bandwidth by using high end systems to compress the data. In this post I will try to take a stab at using message compression.

Create the queue managers and objects

Create two queue managers with the following details - 
Queue Manager Name Listener Port
WQM1 2221
WQM2 2222

Create transmission queues on both the queue managers as follows - 



Queue Manager Name
Transmission Queue
WQM1
WQM2
WQM2
WQM1

Next up, create the sender and the receiver channel that will communicate with each other

Queue Manager Name Sender Channel Receiver Channel
WQM1 WQM1.TO.WQM2 WQM2.TO.WQM1
WQM2 WQM2.TO.WQM1WQM1.TO.WQM2

Create the local queue definition in WQM2 as 'LOCAL.Q' and create a remote queue definition as 'REMOTE.Q.OF.LOCAL.Q' in WQM1. 


If all the objects are created and the channels and listener are running then the message written to REMOTE.Q.OF.LOCAL.Q should end up in LOCAL.Q .

NetTool

For this exercise to keep a tab on the size of the data and the time it takes to send the packets from one queue manager to another, I decided to use NetTool. To know more about NetTool and download, follow this link. Download the zip file and unzip it as a folder in the system.

Protocol Tunneling

Start NetTool by click on the following 'start-nettool.bat' on windows and 'start-nettool.sh' on unix systems and switch to the second tab. This tab allows us to protocol tunnel by having NetTool listen on the port 2222-the listener port for WQM2- and directing the traffic coming on port 2220 to 2222 and click on the 'Listen' button. This will start the tunnel.


With the protocol tunneling in place change the sender channel on WQM1 to use port 2220 instead of 2222. This way we know the time and the data being sent from WQM1 to WQM2.

Without compression

Using RFHUtil, send the message to REMOTE.Q.OF.LOCAL.Q and here is what we see - 



In this scenario a file of 100298 bytes is used to send to the remote queue from WQM1 to WQM2. After the message has been changed, change the compression, right click the channel name and select properties. Change the compression to RLE and save it. Do this to the receive channel as well and restart both the channels. For the sake of parity all the 4 channels have been changed to RLE and need to be restarted.

I changed it across the 2 different message compression and here are the results - 


Starting from top down the order has been ZLIBHIGH, ZLIBFAST, RLE and no compression. The statistics show the progressive message bytes being lowered as the message compression is changed.  







Wednesday, January 6, 2016

IBM Integration Bus using Aggregation Nodes for fan out/fan in

Preface

One of the common requirements that I have come across is having to request data from different systems and present it in a single place. An example of this is when you login on your bank page and you get a single dashboard that will show your -
  1. Checking account summary.
  2. Saving account summary.
  3. Credit Card transaction summary.
  4. Auto loan summary.
  5. Home mortgage summary.
All these details may be residing on a different system and the single denominator may be the customer id that is using these services. Another close use case is if a particular operation needs data for multiple denominations but the external service allows only one request at a time. A case in point is the co-ordinates of the ATM a bank has in the vicinity of a particular zip code while the end system - google maps possibly- only allows one request per service.

One way to work around for this is to use the Aggregation nodes with IBM Integration Bus. In this scenario,the back end application allows only one request at a time. The service we have built receives multiple stock symbols and we use the fan out mechanism to create multiple request for stock quote and then collect them as one response in fan out.

I am using the following web service as the back end application to request the stock quote and the WSDL for that operation is available here.


External/Backend service

In this instance we are using the WSDL to create the external service that will be called from IBM Integration Bus(IIB formerly IBM WebSphere Message Broker). The service receives a request for a stock quote and then replies with the response in SOAP. Create a shared library that will have the web service to get the stock quote. I have named it as 'MFL_StockQuote'



Create the message model that will have the WSDL specification. 



Select the SOAP XML option as our's is a WSDL.



The WSDL already exist, so specify that one for the message model.



Specify the location of the WSDL, in this case the HTTP URL from where you can get the WSDL.



Select the operation that we intend to use for our application. In this case it is the SOAP operations. Click on 'Finish' to complete the operation and import the WSDL.



With the WSDL imported, create the sub flows that will invoke the external service and encapsulate the service invocation.



Named as 'SF_StockQuoteInvoke'

 

Drag and drop the WSDL onto the canvas.


The service will be invoking the web service from the sub flow and the operation will be GetQuote.


To keep things simple I have kept this subflow named as SF_StockQuote. 


After this is done the library content should look like this. To simplify it I have moved the subflows from their schemas to the top level to not use any schemas. 


SF_StockQuote

SF_StockQuote invokes the external service using the WSDL defined details.



The properties of the SOAP Request node.



SF_StockQuoteInvoke

Coming back to SF_StockQuoteInvoke, I have made the following changes to the flow after having had dragged the WSDL onto the canvas- 



The SaveMQHdr compute node will save the incoming MQ Header from the message the Aggregate Request flow is sending. The code snippet used is -

CREATE LASTCHILD OF Environment DOMAIN 'MQMD' NAME 'MQMD' ;
SET Environment.MQMD = InputRoot.MQMD;
SET OutputRoot = InputRoot;

The CreateMQResp compute node is reattaching the will save the incoming MQ Header from the message the Aggregate Request flow is sending. The response that is being sent from the service is being parsed to create a proper XMLNSC message. The code snippet used is -

SET OutputRoot.MQMD = Environment.MQMD;

DECLARE sh NAMESPACE 'http://www.webserviceX.NET/';
DECLARE data CHAR;
SET data  = InputRoot.XMLNSC.sh:GetQuoteResponse.sh:GetQuoteResult;

IF (data = 'exception') THEN
SET OutputRoot.XMLNSC.StockQuotes.Stock = 'exception'; 
ELSE
CREATE LASTCHILD OF OutputRoot 
DOMAIN 'XMLNSC' PARSE (data 
CCSID InputRoot.Properties.CodedCharSetId 
ENCODING 0 ); 
END IF;

Aggregation(Putting it together) 

Till now we have created the service that is going to be invoked. This service will give the stock quote. Next up create the Message Flow application that will have the Aggregation(Fan Out/In). The application is named as 'MFA_AggregationStockQuote'.

Refer the library that has the stock quote service application subflow.


After the Application has been created it should seem like this -


Create the flows that will be needed.

MF_AggReq

This flow will receive the request from service consumer on WebSphere MQ. The format of the message will be like - 

<StockQuote>
<Symbol>WASIX</Symbol>
<Symbol>VDAIX</Symbol>
</StockQuote>

The flow structure looks like this - 


The Aggregate Control is the start of the fan out. The compute node will create the individual request. After all the request are sent to AGG.IN, it will then send the actual message to AGG.CONT.IN. This actual message can be used to relate the actual request to the response.

The request from the consumer may contain the reply to queue and this is also saved for the Aggregate Reply.

DECLARE inRef REFERENCE TO InputRoot.XMLNSC.StockQuote.Symbol[1];
DECLARE sh NAMESPACE 'http://www.webserviceX.NET/';
WHILE LASTMOVE(inRef) DO
SET OutputRoot.MQMD = InputRoot.MQMD;
SET OutputRoot.XMLNSC.sh:GetQuote.sh:symbol = inRef;
PROPAGATE TO TERMINAL 'out';
MOVE inRef NEXTSIBLING REPEAT TYPE NAME;
END WHILE;

CALL CopyMessageHeaders();
SET OutputRoot.BLOB.BLOB = ASBITSTREAM(InputRoot.MQMD, InputRoot.Properties.Encoding, InputRoot.Properties.CodedCharSetId);
PROPAGATE TO TERMINAL 'out1';

MF_AggRep

MF_AggRep flow receives all the response from the services and then fan ins them using Aggregate Reply node. In this flow we also receives the reply from the control flow that contains the request. This request will be used to restore the MQMD of the request. If that is done and it contains the reply to queue the AGG.REP MQOutput node can be discarded and you may use the MQReply node.

Here is the code snippet used in the compute node -

DECLARE inRef REFERENCE TO InputRoot.ComIbmAggregateReplyBody.StockRep;
DECLARE I INT 1;
 
WHILE LASTMOVE(inRef) DO
IF EXISTS(inRef.XMLNSC.StockQuotes[]) THEN
SET OutputRoot.XMLNSC.StockQuotes.Stock[I]=inRef.XMLNSC.StockQuotes.Stock;
SET I = I+1;
ELSE
CREATE NEXTSIBLING OF OutputRoot.Properties 
DOMAIN('MQMD') 
PARSE(inRef.BLOB.BLOB
CCSID inRef.Properties.CodedCharSetId
TYPE 'MQMD');

END IF;
MOVE inRef NEXTSIBLING REPEAT TYPE NAME;
END WHILE;

MF_SvcInvoke

This flow will call the backend service and then send the response back to the queue specified in the MQReply to queue.


MF_AggCont

This flow just sends the message as it received.



If the flow runs successfully the output in the AGG.REP queue should be something like this - 

<StockQuotes>
<Stock>
<Symbol>WASIX</Symbol>
<Last>11.03</Last>
<Date>11/11/2015</Date>
<Time>6:45pm</Time>
<Change>-0.05</Change>
<Open>N/A</Open>
<High>N/A</High>
<Low>N/A</Low>
<Volume>0</Volume>
<MktCap>N/A</MktCap>
<PreviousClose>11.03</PreviousClose>
<PercentageChange>-0.45%</PercentageChange>
<AnnRange>N/A</AnnRange>
<Earns>N/A</Earns>
<P-E>N/A</P-E>
<Name>Wasatch Strategic Income Fund</Name>
</Stock>
<Stock>
<Symbol>VDAIX</Symbol>
<Last>31.23</Last>
<Date>11/11/2015</Date>
<Time>6:45pm</Time>
<Change>-0.11</Change>
<Open>N/A</Open>
<High>N/A</High>
<Low>N/A</Low>
<Volume>0</Volume>
<MktCap>N/A</MktCap>
<PreviousClose>31.23</PreviousClose>
<PercentageChange>-0.35%</PercentageChange>
<AnnRange>N/A</AnnRange>
<Earns>N/A</Earns>
<P-E>N/A</P-E>
<Name>Vanguard Dividend Appreciation </Name>
</Stock>

</StockQuotes>

The code base used for this can be found in the following location.