Spring websockets + Amazon MQ limitations - spring

We want to use spring websockets + STOMP + amazon MQ as a full featured message broker. We were trying to do benchmarking, to find out how many client websocket connections single tomcat node can handle. But it appears that we hit amazonMQ connection limit first. As per the aws documentation, amazonMQ has a limit of 1000 connections per node (as far as I understand we can ask support to increase the limit, but I doubt that it can be increased big time). So my questions is:
1) Am I correct in assuming that for every websocket connection from client to spring/tomcat server, a corresponding connection being opened from server to broker? Is this correct behavior or we're doning something wrong here/missing something?
2) What can be done here? I mean I don't think this is a good idea to create broker node per evry 1000 users..

According to https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.html your are doing everything right, and it is documented behavior.
Quote from javadoc:
For each new CONNECT message, an independent TCP connection to the broker is opened and used exclusively for all messages from the client that originated the CONNECT message. Messages from the same client are identified through the session id message header. Reversely, when the STOMP broker sends messages back on the TCP connection, those messages are enriched with the session id of the client and sent back downstream through the MessageChannel provided to the constructor.
As for a fix, you can write your own message broker relay, with tcp connection pooling.

Related

how to limit number of connections to IBM MQ

I have a Spring Boot based messaging app sending/receiving JMS messages to/from IBM MQ queue manager.
Basically, it uses MQConnectionFactory to organize connection to IBM MQ and a JmsPoolConnectionFactory from messaginghub:pooledjms to enable JMS connection pool, which is removed from MQConnectionFactory in IBM MQ 7.x
The app uses two different appoach to work with JMS. A "correct" one runs a JMSListener to receive messages and then sends a response on each message using JmsTemplate.send(). And there is a second "troubling" approach, where the app sends requests using JmsTemplate.send() and waits for response using JmsTemplate.readByCorrelId() until received or timed out.
I say troubling because this makes JMS sessions last longer if the response is delayed and could easily exhaust IBM MQ connection limit. Unfortunately, I cannot rewrite the app at the moment to the first approach to resolve the issue.
Now I want to restrict the number of connections in the pool. Of course, the delayed requests will fail but IBM MQ connection limit is more important at the moment, so this is kind of appropriate. The problem is that even if I disable the JmsPoolConnectionFactory, it seems that MQConnectionFactory still opens multiple connections to the query manager.
While profiling the app I see multiple threads RvcThread: com.ibm.mq.jmmqi.remote.impl.RemoteTCPConnection#12433875[...] created by JMSCCMasterThreadPool and corresponding connections to the query manager in MQ Explorer. I wonder why there are many of them in spite of the connection pooling is removed from MQConnectionFactory? I suppose it should open and reuse a single connection then but it is not true in my test.
Disabling "troubling" JmsTemplate.readByCorrelId() and leaving only "correct" way in the app removes these multiple connections (and the waiting threads of course).
Replacing JmsPoolConnectionFactory with SingleConnectionFactory has not effect on the issue.
Is there any way to limit those connections? Is it possible to control max threads in the JMSCCMasterThreadPool as a workaround?
Because it affects other applications your MQ admins probably want you to not exhaust the overall Queue Manager's connection limit (MaxChannels and MaxActiveChannels parameters in qm.ini). They can help you by defining an MQ channel exclusively used by your application. By this, they can limit the number of connections of your application with the MAXINST / MAXINSTC channel parameter. You will get an exception when this number is exhausted which is appropriate as you say. Other applications won’t be affected anymore.

How MQ Client like Java Client listen messages from MQ Server running ServerConn Channel

I am looking for detailed description on how IBM MQ Client or listener get the messages from MQ Server when new messages are placed on MQ Queue or Topic.
How the connection between MQ Client and MQ Server are created?
Does MQ Client initiates the connection with Server or does server initiates the connection to its consumer?
In case we have connection pool defined on MQ Client, how client knows that it has to create more connections with Server as the messages are increasing on Server? How Client know about the messages on Server?
Is there a communication from Server to Client which tells client that new messages have arrived?
I am looking for these details not the details on how this is setup or how to setup MQ Channels or Listeners. I am looking for how it works behind the scene.
If someone can point me to the right direction or documentation, it would be great.
It's hard to speak definitively about how the IBM WebSphereMQ client & server work since they're closed source, but based on my experience with other messaging implementations I can provide a general explanation.
A JMS connection is initiated by a client to a server. A JMS client uses a javax.jms.ConnectionFactory to create a javax.jms.Connection which is the connection between the client and server.
Typically when a client uses a pool the pool is either filled "eagerly" (which means a certain number of connections are created when the pool is initialized to fill it to a certain level) or "lazily" (which means the pool is filled with connections one-by-one as clients request them from the pool). If a client requests a connection from the pool and if all the connections in the pool are being used and the maximum size of connections allowed by the pool hasn't been reached then another connection will be created. If the pool has reached its maximum allowed size (i.e no more connections can be created) then the client requesting a connection will have to wait for another client to return their connection to the pool at which point the pool will then give it to the waiting client.
A JMS client can find out about messages on the server in a few different ways.
If the JMS client wants to ask the server occasionally about the messages it has on a particular queue it can create a javax.jms.Consumer and use the receive() method. This method can wait forever for a message to arrive on the queue or it can take a timeout parameter so that if a message doesn't arrive in the specified timeout the call to receive() will return.
If the JMS client wants to receive a message from a particular queue as soon as the message arrives on the queue then it can create a javax.jms.MessageListener implementation and register it on the queue. When such a listener is registered on a queue then when a message arrives on the queue the server will send the message to the listener. This is sometimes referred to as a "callback" since the server is "calling back" to the client.
The first thing you should do is take a course on JMS/IBM MQ or go to the new IBM conference called: Integration Technical Conference
Ok, now to your questions:
How the connection between MQ Client and MQ Server are created?
You simply issue the createQueueConnection method of QueueConnectionFactory class and specify the credentials.
QueueConnection conn = cf.createQueueConnection("myUserId", "myPwd");
Does MQ Client initiates the connection with Server or does server initiates the connection to its consumer?
MQ client application starts the connection - always.
In case we have connection pool defined on MQ Client, how client knows that it has to create more connections with Server as the messages are increasing on Server? How Client know about the messages on Server?
It is up to the team's architect or lead developer to understand message flow and message patterns. Hence, they will know what to set the pool count at. Also, lots and lots of testing too. Some client applications will only require a pool count of 10 whereas other applications may need a pool count of 50 because it is a heavy flow.
Is there a communication from Server to Client which tells client that new messages have arrived?
You use the createReceiver method of the QueueSession class to retrieve a message. Set a timeout value for the createReceiver method rather than continuously polling the queue manager.
Again, some training on the use of JMS/IBM MQ is strongly recommended.

Connect/disconnect from ActiveMQ topic on camel websocket connection/disconnection

I've got the following camel route which listens for messages on an ActiveMQ topic and immediately sends them to all connected web socket clients. This is working fine, but the connection to the topic is made as soon as the route builder is initialised.
from("activemq:topic:mytopic").routeId("routeid").to("websocket://test?sendToAll=true");
What I need is to only connect to the topic when one or more clients are connected to the web socket. Once there are no more connections I want to stop listening on the topic. Is this possible?
According to me there is no proper way to do this. The only way this can be achieved is override Jetty WebSocket code. Once you override Jetty Websocket code you get the flexibility to write your own custom code in open and close websocket.
Maintain a List for all websocket clients in open websocket. Check for close websocket and remove it from the list to know how many are connected or disconnected. Or keep a counter on open and close websocket.
Once all websocket clients get closed suspend the route so that your messages stay in the topic or queue.
If any client gets connected to websocket, resume the route so that the messages reach the particular client connected.

Are AMQP connections (RabbitMQ) between Cloundfoundry applications possible?

I have two applications deployed on Cloudfoundry: a service application that computes stuff (aka computeService) and a client application that renders html for us mortals to hit buttons on (aka clientService). I would like a controller in the clientService to send commands to the computeService (when mortals hit buttons). The broker and the computeService run on the same machine.
I know I cannot make remote AMQP connections into a service on cloudfoundry.com, but I assume I can make connections between applications. However, every sensible address combination for broker and clientService gives me the same error:
javax.jms.JMSException: Could not connect to broker URL: tcp://127.0.0.1:61616. Reason: java.net.ConnectException: Connection refused
Whatever address I try, I cannot post to the queue. The code works flawlessly on my local machine.
My question: can I use RabbitMQ to pass messages between the two applications on Cloudfoundry? And if so, which addresses should I use?
Thanx!
One way to try this out is to create two replicas of the rabbit message example at Spring Samples
...a message sender and a message receiver. When deployed, they should share the same rabbit service.
I pushed the rabbit message which worked for me to: rabbitmessage-sndrcv

RabbitMQ with Websocket and Gevent

I'm looking forward to develop a realtime API for my web application using Websocket. For this I'm using RabbitMQ as the broker and My backend is based on python (gevent + websocket),and Pika/Puka as rabbitmq client.
The problem I'm facing here is that, how we can use websocket to connect with rabbitMQ. After the initial websocket connection establishment, the socket object wait for new messages from client, and in the case of rabbitMQ, we need to setup a consumer for it, so it will process the message when it receive one. We can take this in this way,
Clients are established connection with server via full-duplex websocket.
All clients should act as RabbitMQ's consumer after initial websocket handshake, so they all get updates when a client gets some message.
When new message arrives at websocket, that client will send it to RabbitMQ, so at this time this client act as publisher.
The problem is Websocket wait for a new message, and the RabbitMQ consumer wait for new message on its channel, I'm failed to link these two cases.
I'm not sure whether this is a wrong method ...
I'm unable to find a method to implement this scenario.If I'm going wrong way or is there any alternate method ?, please help me to fix this.
Thank you,
Haridas N.
I implemented similar requirement with Tornado + websocket + RabbitMQ + Pika.
I think this were already known method. Here is my git repo for this web chat application.
https://github.com/haridas/RabbitChat
It seems very difficult to the similar thing with gevent/twisted because the rabbitMQ clients couldn't supporting the event loops of gevent/twisted.
The pika has tornado adapter, so that makes this easy to setup. Pika development team working on the twisted adapter also. I hope they will release it very soon.
Thanks,
Haridas N.
http://haridas.in.
A simple solution would be to use gevent.queue.Queue instances for inter-greenlet communication.

Resources