As per our configuration, we have WAS version is 8.5.5.1, IBM MQ version 7.5.0.3. We are using 2 channels to connect to WMQ, one with MAXINST set to 250 and one with 500. SHARECNV is set to 10 for both. Now we have an upper limit of making maximum 1600 connections in a queue manager but we end up crossing that limit after 3-4 days of continuous running of WAS Server.
I want to understand how parameters on WAS side affect this count. We are using Queue Connection Factory and Act Spec for making the connections and we have 23 of each of them. Out of these for 22 the settings in Act Spec and QCF are kept default like max server sessions=10, max connection in connection pool=10, max sessions in session pool set to 10. This services have quite low tps of around 15-20 request per minute. All 22 of them use same channel to connect to queue manager with MAXINST set to 250. 1 gets quite high load with peak of 80 requests per second(aprox 40 per server) for which max server sessions=40, max connection in connection pool=40, max sessions in session pool is set to 10.Connection Timeout, Reap Time, Unused Timeout and Aged timeout values are kept default for all.
With these settings we end up making around 1200 connection on the channel used by 22 services and around 500 for the other channel after 2-3 days of continuous running. These build up over a period of time.
Now I want to tune these settings so that we don't end up crossing the connection count limit and also don't end up having no connections available.
So I have a few questions:
What is a better option from performance point of view- reducing max connections in connection pool or max sessions in sessions pool. What should be the ideal values for the load mentioned earlier.
What should be the ideal value for Unused Timeout for Connection Pool and Session Pool which is set to 30 mins by default. If we reduce it to say 5 mins, what implications could it have on performance of failure to get the connections.
Is there some setting that can be done at WMQ side so that the idle/unused connections are closed or this can happen only from the client side.
DISCINT parameter value is set to zero and HBINT to 300. What should be the ideal value.
I ran below command to view the connections
echo "DIS CONN(*) TYPE(*) CONNAME CHANNEL OBJNAME OBJTYPE" | mqsc -e -m QM-p width=1000 | grep -o '^\w\+:\|\w\+[(][^)]\+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CHANNEL" in p) { print p["CHANNEL"], p["CURSHCNV"], p["CONNAME"],p["CHSTADA"],p["CHSTATI"],p["LSTMSGDA"],p["LSTMSGTI"],p["OBJNAME"],p["OBJTYPE"],p["ASTATE"] } } /^\w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }' | grep MYCHANNEL
MYCHANNEL,,10.215.161.65,,,,,,,NONE
MYCHANNEL,,10.215.161.65,,,,,,,SUSPENDED
MYCHANNEL,,10.215.161.65,,,,,MYQUEUE01,QUEUE,ACTIVE
I can see a lot of connection in None and suspended state which do not have any OBJNAME or OBJTYPE associated.
I have tried simulating the issue in Test and same thing happens and these connections keeps on increasing as we keep in hitting requests. Can someone tell me why these connections are getting created. Also it looks like these connections will never be used by the application.
This is how connection are made and closed in the application:
We have an abstrack bean class which is extended by all MDB's
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class TrackBeanV2 extends AbstractServiceBean implements MessageListener {//code}
The abstrack bean handles creation and closing of connections in following manner:
public abstract class AbstractServiceBean {
#Resource(name = "myQCF", type = QueueConnectionFactory.class, shareable = true, description = "Reply Connection Factory")
private ConnectionFactory replyCF;
#PostConstruct
private void postConstruct() {
replyConnection = replyCF.createConnection();
} catch (JMSException e) {
throw new RuntimeException("Failed to create JMS Connection");
}
}
#PreDestroy
private void preDestroy() {
try {
replyConnection.close();
} catch (JMSException e) {
throw new RuntimeException("Failed to close JMS connection", e);
}
}
private void sendResponseMessage(String outputMessageText, String jmsMessageID , Destination replyDestination) {
TextMessage replyMessage = null;
try {
createSession();
createProducer();
replyMessage = createReplyMessage(outputMessageText , jmsMessageID);
sendReply(replyMessage, replyDestination);
closeProducer();
closeSession();
} catch (JMSException exp) {
handleException(exp);
}
}
private void createSession() throws JMSException{
replySession = replyConnection.createSession(true, 0);
}`
private void createProducer() throws JMSException{
replyProducer = replySession.createProducer(null);
}
private void closeSession() throws JMSException {
if (replySession != null) {
replySession.close();
}
}
private void closeProducer() throws JMSException{
if (replyProducer != null) {
replyProducer.close();
}
}
private void sendReply(TextMessage replyMessage, Destination replyDestination) throws JMSException {
logMessages(replyMessage.getText(), "RESPONSE MESSAGE");
replyProducer.send(replyDestination, replyMessage);
}
I have not added other methods of the class which marshalling/unmarshalling and other stuff.
After doing lot more analysis and trying out different WAS and MQ settings, we ruled out any issue with configuration and code. While researching found following link http://www-01.ibm.com/support/docview.wss?uid=swg21605479. The issue was with Wily Introscope tool used to monitor the WAS server, it was making connections with MQ and not releasing them. We removed the monitoring from the Server and it is working fine since then. Thanks everyone here for their support.
There is a IBM developerWorks blog post "Avoiding run-away numbers of channels" by #MoragHughson that goes into detail about the various settings on a queue manager to limit total maximum channels for the entire queue manager (MaxChannels in qm.ini), a single channel (MAXINST), and a single client machine connecting to a channel (MAXINSTC).
There is MQGem Software blog post "MaxChannels vs DIS QMSTATUS CONNS" also by #MoragHughson (Thank you Morag for the helpful posts) that goes into detail on the differences between a connections (DIS CONN) and channels (DIS CHS).
Below are a few commands that can help with reconciling things (note I've tested these on Linux, if you are running on another OS and they don't work let me know and I'll try and provide a working example for that OS):
The command below will show you the connection identifier, channel name associated to the connection if any, and the IP address if any, the output is CONN,CHANNEL,CONNAME.
echo "DIS CONN(*) CHANNEL CONNAME"|runmqsc <QMGR> | grep -o '^\w\+:\|\w\+[(][^)]\+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CONN" in p) { print p["CONN"], p["CHANNEL"], p["CONNAME"] } } /^\w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }'
The command below will show you each running channel instance, the number of shared conversations, and the IP address connecting to the channel, the output is CHANNEL,CURSHCNV,CONNAME.
echo "DIS CHS(*) ALL"|runmqsc <QMGR> | grep -o '^\w\+:\|\w\+[(][^)]\+[)]' | awk -F '[()]' -v OFS="," 'function printValues() { if ("CHANNEL" in p) { print p["CHANNEL"], p["CURSHCNV"], p["CONNAME"] } } /^\w+:/ { printValues(); delete p; next } { p[$1] = $2 } END { printValues() }'
Both of the above commands can by adapted to use the mqsc program that you showed you use in your comments.
We had a similar problem where the connection count used to reach its limit once the application was kept active for hours.
Our catch was to call disconnect() of the queue manager post enqueue or dequeue rather than close(). So make sure your finally block looks something like this.
finally
{
queue.close();
qMgr.disconnect(); //rather than qMgr.close();
}
Related
I need to redeliver a message if it can't be processed, for example because of some external endpoint failure. So I'm using following MDB configuration (it worth to mention that I'm using openMQ (Glassfish 4.1)):
#MessageDriven(mappedName = "MyQueue", name = "MyQueue", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryAttempts", propertyValue = "10"),
#ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryInterval", propertyValue = "30000")})
Here's onMessage() method:
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void onMessage (Message message)
{
try
{
//some processing here
}
catch (JMSException jmsException)
{
logger.log (Level.SEVERE, "Exception processing notification message", jmsException);
}
catch (BackingStoreException e)
{
// because of throwing RuntimeException, the message is going to be redelivered according to mdb configuration params(interval and attempts count)
throw new RuntimeException ();
}
}
In order to redeliver a message it's also possible to rollback a transaction, however openMQ lacks the property for redelivery interval, so it doesn't suites me:
https://github.com/javaee/openmq/issues/220
https://github.com/javaee/openmq/issues/23
https://github.com/javaee/openmq/issues/134
All in all, redelivery works fine, besides one moment: if message is going to be redelivered, mdb doesn't release the connection and holds it for endpointExceptionRedeliveryInterval * endpointExceptionRedeliveryAttempts, in my case 5 minutes. So, cause the default values for maxPoolSize is 32, 32 "bad" messages are enough to block the mdb.
Is there are way to release the connection in case of message redelivering?
This is the expected behavior as per JMS specification and I do not think that there could be some way to release the connection object while some sort of message processing is under progress. Read JMS specs here and below is relevant except from "4.3.5 Closing a Connection":
If one or more of the connection’s session’s message listeners is
processing a message at the point connection close is invoked, all the
facilities of the connection and it’s sessions must remain available
to those listeners until they return control to the JMS provider.
When connection close is invoked it should not return until message
processing has been orderly shut down. This means that all message
listeners that may have been running have returned and that all
pending receives have returned.
I am not sure why you want to use such high numbers for retry mechanism, 10 attempts are too big to go for, maximum I have seen till now is 3 times, I think you can try to adjust your retry mechanism numbers, or may be having another connection which is dedicated to re-delivery.
I have some Java code that reads messages from an ActiveMQ queue. The code uses a JmsTemplate from Spring and I use the "browseSelected" method to retrieve any messages from the queue that have a timestamp in their header older than 7 days (by creating the appropriate criteria as part of the messageSelector parameter).
myJmsTemplate.browseSelected(myQueue, myCriteria, new BrowserCallback<Integer>() {
#Override
public Integer doInJms(Session s, QueueBrowser qb) throws JMSException {
#SuppressWarnings("unchecked")
final Enumeration<Message> e = qb.getEnumeration();
int count = 0;
while (e.hasMoreElements()) {
final Message m = e.nextElement();
final TextMessage tm = (TextMessage) MyClass.this.jmsQueueTemplate.receiveSelected(
MyClass.this.myQueue, "JMSMessageID = '" + m.getJMSMessageID() + "'");
myMessages.add(tm);
count++;
}
return count;
}
});
The BrowserCallback's "doInJms" method adds the messages which match the criteria to a list ("myMessages") which subsequently get processed further.
The issue is that I'm finding the code will only process 400 messages each time it runs, even though there are several thousand messages which match the criteria specified.
When I previously used another queueing technology with this code (IBM MQ), it would process all records which met the criteria.
I'm wondering whether I'm experiencing an issue with ActiveMQ's prefetch limit: http://activemq.apache.org/what-is-the-prefetch-limit-for.html
Versions: ActiveMQ 5.10.1 and Spring 3.2.2.
Thanks in advance for any assistance.
The broker will only return up to 400 message by default as configured by the maxBrowsePageSize option in the destination policies. You can increase that value but must use caution as the messages are paged into memory and as such can lead you into an OOM situation.
You must always remember that a message broker is not a database, using it as one will generally end in tears.
I'm currently having a problem with jms synchronous request/reply approach, this is what happens:
1.) ProgramA create a jms message, a temporary queue and set it as a replyTo.
2.) ProgramB has a listener to the message created from ProgramA, process the message and reply to it. But ProgramB needs to communicate to a 3rd party web service that sometimes takes more than 10seconds to reply, and that is the problem I set the consumer to listen for 5000 (5s) and of course it will timeout afterwards. So the message is not received.
My observation:
1.) Even though ProgramA is done reading (no reply yet, at that instant I try to delete the temporary queue). It's not able to and ProgramB was still able to write to the reply queue, but nobody's going to read that message (too late).
When I try to change 5s to 20s listen time the problem was solved, but is it the right approach?
Also is it possible for the ProgramB to not try to write to the queue when ProgramA has stop reading?
Partial codes:
Destination replyQueue = send(jmsUtil, actionDTO);
SalesOrderResponseDTO responseDTO = readReply(jmsUtil, replyQueue, actionDTO);
public Destination send(JmsSessionUtil jmsUtil, SalesOrderActionDTO soDTO) {
try {
utx.begin();
jmsUtil.send(soDTO, null, 0L, 1, Long.parseLong(configBean.getProperty("jms.payrequest.timetolive")), true);
utx.commit();
return jmsUtil.getReplyQueue();
} catch (Exception e) {
try {
utx.rollback();
} catch (Exception e1) {
}
}
return null;
}
public SalesOrderResponseDTO readReply(JmsSessionUtil jmsUtil, Destination replyQueue, SalesOrderActionDTO actionDTO) {
SalesOrderResponseDTO responseDTO = null;
try {
utx.begin();
responseDTO = (SalesOrderResponseDTO) jmsUtil.read(replyQueue);
if (responseDTO != null) {
// fires the response event
SalesOrderResponsePayload eventPayload = new SalesOrderResponsePayload();
eventPayload.setResponseDTO(responseDTO);
responseEvent.fire(eventPayload);
} else { // timeout
((TemporaryQueue) replyQueue).delete();
jmsUtil.dispose();
}
utx.commit();
return responseDTO;
} catch (Exception e) {
try {
utx.rollback();
} catch (Exception e1) {
}
}
return responseDTO;
}
public String send(MessageDTO messageDTO,
JMSQueueEnum resultNotificationQueue, Long parentProcessId,
int JMSPriority, long timeToLive, boolean hasReply)
throws JMSException, InvalidDTOException, NamingException {
try {
// Process optional parameters
messageDTO.setResultNotificationQueue(resultNotificationQueue);
messageDTO.setParentProcessId(parentProcessId);
// Wrap MessageDTO in a JMS ObjectMessage
ObjectMessage msg = MessageDTOHelper.serialize(session, messageDTO);
msg.setJMSType(messageDTO.getClass().getSimpleName());
msg.setStringProperty("DTOType", messageDTO.getClass()
.getSimpleName());
requestProducer = session.createProducer(queue);
if (hasReply) {
replyQueue = session.createTemporaryQueue();
replyConsumer = session.createConsumer(replyQueue);
msg.setJMSReplyTo(replyQueue);
}
if (JMSPriority > -1) {
requestProducer.send(msg, DeliveryMode.PERSISTENT, JMSPriority,
timeToLive);
} else {
// Send the JMS message
requestProducer.send(msg);
}
return msg.getJMSMessageID();
} catch (Exception e) {
}
return null;
}
public MessageDTO read(Destination replyQueue) throws JMSException,
NamingException {
if (replyQueue instanceof Queue) {
Message msg = replyConsumer.receive(20000);
if (msg == null) {
return null;
}
MessageDTO messageDTO = MessageDTOHelper
.deserialize((ObjectMessage) msg);
return messageDTO;
} else {
}
return null;
}
Actual question here is whether you need synchronous or asynchronous communication.
I would always prefer asynchronous, and it seems from your question that there is no need for synchronous communication neither in your case. However, if there is some reason for synchronous then you are stuck with temporary queues - you'll have to specify timeout interval and you'll face problems expressed in your question. If Program A can wait, raise the timeout interval although that's far from optimal. As far as I know, there is no possibility for Program B to check if A still listens.
In case of asynchronous communication, you have (at least) two JMS options:
Using different message queues - Program A sends the message on Queue1 and finishes, but listens (e.g. through Message Driven Bean) on Queue2 where Program B puts its response when it's done. Small drawback is usage of one extra pair of producer and consumer.
Using same message queue - Program A and Program B both send and receive messages on Queue1, but with different message selector (see description here). Basically, message selectors will filter messages for specific listener and thus enable using same queue for bidirectional communication.
See also:
JMS Synchronous Message Consumption
You could have A add a header to its message with the current timestamp + 5 secs. When B receives the response from the 3rd party, if the current time is greater than the header, it should drop the result and not send. You could use the time-to-live jms message property for this, although that is not its express purpose.
I have a simple code to put 2 messages into a queue.
1) I set the connectionNameList with two servers.
2) Those two servers are independent, but have the same Queue Manager and Queue defined with same name, such as "QMgr" and "TEST.IN"
3) I set the setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
I hope when the first server is down, it should send the messages to 2nd one.
The test I did:
a) I send first message, sender.send(message); It worked.
b) sleep 30 seconds.
During this time, I shutdown the first server
c) then sleep done, try to send 2nd message, but it failed to send immediately
Further more, I tried more, I did try{} catch{} for 2nd message, and in the catch{}, I try to sender.send(message), it still fails.
Any idea why it is different than what I expected. I will really appreciate your reply.
public static void main(String[] args) throws Exception
{
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
cf.setConnectionNameList("10.230.34.191(1418),10.230.34.169(1418)");
cf.setQueueManager("QMgr");
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
cf.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
cf.setClientReconnectTimeout(600);
System.out.println("connect list " + cf.getConnectionNameList());
MQQueueConnection connection = (MQQueueConnection) cf
.createQueueConnection("mqm", "passwd");
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("queue:///TEST.IN");
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
long uniqueNumber = System.currentTimeMillis() % 1000;
JMSTextMessage message = (JMSTextMessage) session.createTextMessage("SimplePTP "
+ uniqueNumber);
// Start the connection
connection.start();
sender.send(message);
System.out.println("Sent message:\\n" + message);
System.out.println("sleep 30 seconds");
Thread.sleep(30000);
uniqueNumber = System.currentTimeMillis() % 1000;
message = (JMSTextMessage) session.createTextMessage("SimplePTP " + uniqueNumber);
sender.send(message);
sender.close();
session.close();
connection.close();
System.out.println("\\nSUCCESS\\n");
}
Well this is the simplest test case and should have worked. How did you bring down the first queue manager? Did you down it with a -r option. Remember, without the -r option the clients will not reconnect when queue manager is ended with endmqm command.
endmqm -r <qm name>
Assuming you used -r option and it still did not work, then my suggestion would be to try the following:
Set an exception listener to know what is going on with reconnection. Exception listener would be invoked when the connection is broken and reconnection attempt starts till either reconnection is successful or fails. Exception listener sample code would be something like this:
conn.setExceptionListener(new ExceptionListener() {
public void onException(JMSException e) {
System.out.print(e);
}
});
I'm looking to increase the performance of a high-throughput producer that I'm writing against ActiveMQ, and according to this useAsyncSend will:
Forces the use of Async Sends which adds a massive performance boost;
but means that the send() method will return immediately whether the
message has been sent or not which could lead to message loss.
However I can't see it making any difference to my simple test case.
Using this very basic application:
const string QueueName = "....";
const string Uri = "....";
static readonly Stopwatch TotalRuntime = new Stopwatch();
static void Main(string[] args)
{
TotalRuntime.Start();
SendMessage();
Console.ReadLine();
}
static void SendMessage()
{
var session = CreateSession();
var destination = session.GetQueue(QueueName);
var producer = session.CreateProducer(destination);
Console.WriteLine("Ready to send 700 messages");
Console.ReadLine();
var body = new byte[600*1024];
Parallel.For(0, 700, i => SendMessage(producer, i, body, session));
}
static void SendMessage(IMessageProducer producer, int i, byte[] body, ISession session)
{
var message = session.CreateBytesMessage(body);
var sw = new Stopwatch();
sw.Start();
producer.Send(message);
sw.Stop();
Console.WriteLine("Running for {0}ms: Sent message {1} blocked for {2}ms",
TotalRuntime.ElapsedMilliseconds,
i,
sw.ElapsedMilliseconds);
}
static ISession CreateSession()
{
var connectionFactory = new ConnectionFactory(Uri)
{
AsyncSend = true,
CopyMessageOnSend = false
};
var connection = connectionFactory.CreateConnection();
connection.Start();
var session = connection.CreateSession(AcknowledgementMode.AutoAcknowledge);
return session;
}
I get the following output:
Ready to send 700 messages
Running for 2430ms: Sent message 696 blocked for 12ms
Running for 4275ms: Sent message 348 blocked for 1858ms
Running for 5106ms: Sent message 609 blocked for 2689ms
Running for 5924ms: Sent message 1 blocked for 2535ms
Running for 6749ms: Sent message 88 blocked for 1860ms
Running for 7537ms: Sent message 610 blocked for 2429ms
Running for 8340ms: Sent message 175 blocked for 2451ms
Running for 9163ms: Sent message 89 blocked for 2413ms
.....
Which shows that each message takes about 800ms to send and the call to session.Send() blocks for about two and a half seconds. Even though the documentation says that
"send() method will return immediately"
Also these number are basically the same if I either change the parallel for to a normal for loop or change the AsyncSend = true to AlwaysSyncSend = true so I don't believe that the async switch is working at all...
Can anyone see what I'm missing here to make the send asynchronous?
After further testing:
According to ANTS performance profiler that vast majority of the runtime is being spent waiting for synchronization. It appears that the issue is that the various transport classes block internally through monitors. In particular I seem to get hung up on the MutexTransport's OneWay method which only allows one thread to access it at a time.
It looks as though the call to Send will block until the previous message has completed, this explains why my output shows that the first message blocked for 12ms, while the next took 1858ms. I can have multiple transports by implementing a connection-per-message pattern which improves matters and makes the message sends work in parallel, but greatly increases the time to send a single message, and uses up so many resources that it doesn't seem like the right solution.
I've retested all of this with 1.5.6 and haven't seen any difference.
As always the best thing to do is update to the latest version (1.5.6 at the time of this writing). A send can block if the broker has producer flow control enabled and you've reached a queue size limit although with async send this shouldn't happen unless you are sending with a producerWindowSize set. One good way to get help is to create a test case and submit it via a Jira issue to the NMS.ActiveMQ site so that we can look into it using your test code. There have been many fixes since 1.5.1 so I'd recommend giving that new version a try as it could already be a non-issue.