You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomee.apache.org by Jonathan Gallimore <jo...@gmail.com> on 2023/02/16 11:46:25 UTC

Connections to ActiveMQ brokers

One of the things I've been looking into recently is the number of
connections that TomEE will make to an ActiveMQ broker. If you consider an
application that has 10 Message Driven Beans, and another bean that sends
messages using a connection factory, that application when started will
make 20 connections to ActiveMQ - 10 for the connection pool, and an
additional connection for each message driven bean.

Conversely, I could create (and it occurs to me that I should) a Spring
application that listens on 10 destinations, sends messages from another
bean, and uses just 1 connection: a JMS connection is capable of managing
several sessions at the same time. At a small scale, the number of
connections isn't an issue, but if you have hundreds of applications
connecting to ActiveMQ, each making dozens of connections, this can become
a bit of a challenge.

There are some options around this:

* Have the MDBs use connections from the connection pool - this is already
possible using an activation property "ConnectionFactoryLookup", for
example:

    <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter"

class-name="org.apache.openejb.resource.activemq.ActiveMQResourceAdapter">
        # Do not start the embedded ActiveMQ broker
        BrokerXmlConfig  =
        ServerUrl = tcp://localhost:61616
        UserName system
        Password manager
    </Resource>

    <Resource id="MyJmsConnectionFactory"
type="javax.jms.ConnectionFactory">
        ResourceAdapter = MyJmsResourceAdapter
        PoolMaxSize 10
        PoolMinSize 0
    </Resource>

    <Container id="MyJmsMdbContainer" ctype="MESSAGE">
        ResourceAdapter = MyJmsResourceAdapter
        activation.ConnectionFactoryLookup=MyJmsConnectionFactory
    </Container>

This means that the connections for the message driven beans will come from
the same pool as connections used to send messages, so you can at least
manage the full set. You'll still need at least <number of mdbs> + 1
connections in that pool, however.

* Override the resource adapter behaviour where connections are created.
Connections are made here:
https://github.com/apache/tomee/blob/main/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/TomEEManagedConnectionFactory.java#L67.
I hacked up some code to override makeConnection():

private final Map<ActiveMQConnectionRequestInfo, ActiveMQConnection>
physicalConnections = new HashMap<>();

    @Override
    public ActiveMQConnection makeConnection(ActiveMQConnectionRequestInfo
connectionRequestInfo, ActiveMQConnectionFactory connectionFactory) throws
JMSException {
        ActiveMQConnection activeMQConnection = null;

        if (singleton) {
            synchronized (this) {
                activeMQConnection =
physicalConnections.get(connectionRequestInfo);
                if (activeMQConnection == null) {
                    activeMQConnection =
super.makeConnection(connectionRequestInfo, connectionFactory);
                    physicalConnections.put(connectionRequestInfo,
activeMQConnection);
                }
            }
        } else {
            activeMQConnection =
super.makeConnection(connectionRequestInfo, connectionFactory);
        }

        return activeMQConnection;
    }

The idea here is that only one physical connection per
username/password/client ID combination would be created, and can be shared
by different sessions. I added a parameter to the connection factory called
"singleton" (perhaps needs a better name) to turn this behaviour on.

The good news is that broadly speaking, it does work - I'm working on some
itests, but unit tests and actually running TomEE and ActiveMQ look good.

Does anyone have any thoughts or reservations on this (or any specific
cases that ought to be tested)?

Jon

Re: Connections to ActiveMQ brokers

Posted by "Jonathan S. Fisher" <ex...@gmail.com>.
Hey Jonathan :)

I'm still interested in testing this out if you'd like. I applied your
patch to 8.0.14 (minus the singleton property) and it does seem to start
up. In the ActiveMQ Broker console I can now see that I have multiple
consumers on one connection. Win.

One thing that might be important: We create two connectionFactories in our
tomee.xml, a non-XA and an XA. Some of our outbound messages we want
attached to the transaction (like sending an email, updating the database;
all or nothing), some of them we don't (sending a message to another
application and waiting for a response on a temporary queue). Most of, but
not all of, our MDBs are transactional: We have MDBs that listen on topics
for things like cache eviction notices that don't involve any XA resources.
I feel like the reason we have to create two connection factories for XA
and non-XA was that using a XA connection outside of a transaction never
sent messages, or it leaked or something. Can't remember.

Anyway, at the surface it does seem to work and significantly cuts down on
open TCP connections.

cheers,




On Mon, Mar 13, 2023 at 9:48 PM Jonathan Fisher <ex...@gmail.com> wrote:

> Old thread, but I think this is a great idea. If you kick a PR or need
> assistance writing one, I’m happy to help and also take it for a spin in
> our test environment… we push a ton of messages through activemq and the
> amount of tcp connections is not optimal!
>
> Sent from my iPhone
>
> > On Feb 16, 2023, at 5:47 AM, Jonathan Gallimore <
> jonathan.gallimore@gmail.com> wrote:
> >
> > One of the things I've been looking into recently is the number of
> > connections that TomEE will make to an ActiveMQ broker. If you consider
> an
> > application that has 10 Message Driven Beans, and another bean that sends
> > messages using a connection factory, that application when started will
> > make 20 connections to ActiveMQ - 10 for the connection pool, and an
> > additional connection for each message driven bean.
> >
> > Conversely, I could create (and it occurs to me that I should) a Spring
> > application that listens on 10 destinations, sends messages from another
> > bean, and uses just 1 connection: a JMS connection is capable of managing
> > several sessions at the same time. At a small scale, the number of
> > connections isn't an issue, but if you have hundreds of applications
> > connecting to ActiveMQ, each making dozens of connections, this can
> become
> > a bit of a challenge.
> >
> > There are some options around this:
> >
> > * Have the MDBs use connections from the connection pool - this is
> already
> > possible using an activation property "ConnectionFactoryLookup", for
> > example:
> >
> >    <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter"
> >
> >
> class-name="org.apache.openejb.resource.activemq.ActiveMQResourceAdapter">
> >        # Do not start the embedded ActiveMQ broker
> >        BrokerXmlConfig  =
> >        ServerUrl = tcp://localhost:61616
> >        UserName system
> >        Password manager
> >    </Resource>
> >
> >    <Resource id="MyJmsConnectionFactory"
> > type="javax.jms.ConnectionFactory">
> >        ResourceAdapter = MyJmsResourceAdapter
> >        PoolMaxSize 10
> >        PoolMinSize 0
> >    </Resource>
> >
> >    <Container id="MyJmsMdbContainer" ctype="MESSAGE">
> >        ResourceAdapter = MyJmsResourceAdapter
> >        activation.ConnectionFactoryLookup=MyJmsConnectionFactory
> >    </Container>
> >
> > This means that the connections for the message driven beans will come
> from
> > the same pool as connections used to send messages, so you can at least
> > manage the full set. You'll still need at least <number of mdbs> + 1
> > connections in that pool, however.
> >
> > * Override the resource adapter behaviour where connections are created.
> > Connections are made here:
> >
> https://github.com/apache/tomee/blob/main/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/TomEEManagedConnectionFactory.java#L67
> .
> > I hacked up some code to override makeConnection():
> >
> > private final Map<ActiveMQConnectionRequestInfo, ActiveMQConnection>
> > physicalConnections = new HashMap<>();
> >
> >    @Override
> >    public ActiveMQConnection makeConnection(ActiveMQConnectionRequestInfo
> > connectionRequestInfo, ActiveMQConnectionFactory connectionFactory)
> throws
> > JMSException {
> >        ActiveMQConnection activeMQConnection = null;
> >
> >        if (singleton) {
> >            synchronized (this) {
> >                activeMQConnection =
> > physicalConnections.get(connectionRequestInfo);
> >                if (activeMQConnection == null) {
> >                    activeMQConnection =
> > super.makeConnection(connectionRequestInfo, connectionFactory);
> >                    physicalConnections.put(connectionRequestInfo,
> > activeMQConnection);
> >                }
> >            }
> >        } else {
> >            activeMQConnection =
> > super.makeConnection(connectionRequestInfo, connectionFactory);
> >        }
> >
> >        return activeMQConnection;
> >    }
> >
> > The idea here is that only one physical connection per
> > username/password/client ID combination would be created, and can be
> shared
> > by different sessions. I added a parameter to the connection factory
> called
> > "singleton" (perhaps needs a better name) to turn this behaviour on.
> >
> > The good news is that broadly speaking, it does work - I'm working on
> some
> > itests, but unit tests and actually running TomEE and ActiveMQ look good.
> >
> > Does anyone have any thoughts or reservations on this (or any specific
> > cases that ought to be tested)?
> >
> > Jon
>


-- 
Jonathan | exabrial@gmail.com
Pessimists, see a jar as half empty. Optimists, in contrast, see it as half
full.
Engineers, of course, understand the glass is twice as big as it needs to
be.

Re: Connections to ActiveMQ brokers

Posted by Jonathan Fisher <ex...@gmail.com>.
Old thread, but I think this is a great idea. If you kick a PR or need assistance writing one, I’m happy to help and also take it for a spin in our test environment… we push a ton of messages through activemq and the amount of tcp connections is not optimal!

Sent from my iPhone

> On Feb 16, 2023, at 5:47 AM, Jonathan Gallimore <jo...@gmail.com> wrote:
> 
> One of the things I've been looking into recently is the number of
> connections that TomEE will make to an ActiveMQ broker. If you consider an
> application that has 10 Message Driven Beans, and another bean that sends
> messages using a connection factory, that application when started will
> make 20 connections to ActiveMQ - 10 for the connection pool, and an
> additional connection for each message driven bean.
> 
> Conversely, I could create (and it occurs to me that I should) a Spring
> application that listens on 10 destinations, sends messages from another
> bean, and uses just 1 connection: a JMS connection is capable of managing
> several sessions at the same time. At a small scale, the number of
> connections isn't an issue, but if you have hundreds of applications
> connecting to ActiveMQ, each making dozens of connections, this can become
> a bit of a challenge.
> 
> There are some options around this:
> 
> * Have the MDBs use connections from the connection pool - this is already
> possible using an activation property "ConnectionFactoryLookup", for
> example:
> 
>    <Resource id="MyJmsResourceAdapter" type="ActiveMQResourceAdapter"
> 
> class-name="org.apache.openejb.resource.activemq.ActiveMQResourceAdapter">
>        # Do not start the embedded ActiveMQ broker
>        BrokerXmlConfig  =
>        ServerUrl = tcp://localhost:61616
>        UserName system
>        Password manager
>    </Resource>
> 
>    <Resource id="MyJmsConnectionFactory"
> type="javax.jms.ConnectionFactory">
>        ResourceAdapter = MyJmsResourceAdapter
>        PoolMaxSize 10
>        PoolMinSize 0
>    </Resource>
> 
>    <Container id="MyJmsMdbContainer" ctype="MESSAGE">
>        ResourceAdapter = MyJmsResourceAdapter
>        activation.ConnectionFactoryLookup=MyJmsConnectionFactory
>    </Container>
> 
> This means that the connections for the message driven beans will come from
> the same pool as connections used to send messages, so you can at least
> manage the full set. You'll still need at least <number of mdbs> + 1
> connections in that pool, however.
> 
> * Override the resource adapter behaviour where connections are created.
> Connections are made here:
> https://github.com/apache/tomee/blob/main/container/openejb-core/src/main/java/org/apache/openejb/resource/activemq/jms2/TomEEManagedConnectionFactory.java#L67.
> I hacked up some code to override makeConnection():
> 
> private final Map<ActiveMQConnectionRequestInfo, ActiveMQConnection>
> physicalConnections = new HashMap<>();
> 
>    @Override
>    public ActiveMQConnection makeConnection(ActiveMQConnectionRequestInfo
> connectionRequestInfo, ActiveMQConnectionFactory connectionFactory) throws
> JMSException {
>        ActiveMQConnection activeMQConnection = null;
> 
>        if (singleton) {
>            synchronized (this) {
>                activeMQConnection =
> physicalConnections.get(connectionRequestInfo);
>                if (activeMQConnection == null) {
>                    activeMQConnection =
> super.makeConnection(connectionRequestInfo, connectionFactory);
>                    physicalConnections.put(connectionRequestInfo,
> activeMQConnection);
>                }
>            }
>        } else {
>            activeMQConnection =
> super.makeConnection(connectionRequestInfo, connectionFactory);
>        }
> 
>        return activeMQConnection;
>    }
> 
> The idea here is that only one physical connection per
> username/password/client ID combination would be created, and can be shared
> by different sessions. I added a parameter to the connection factory called
> "singleton" (perhaps needs a better name) to turn this behaviour on.
> 
> The good news is that broadly speaking, it does work - I'm working on some
> itests, but unit tests and actually running TomEE and ActiveMQ look good.
> 
> Does anyone have any thoughts or reservations on this (or any specific
> cases that ought to be tested)?
> 
> Jon