ActiveMQ“连接池”使用

1. ActiveMQ的连接池

ActiveMQ提供了PoolConnectionFactory、PoolConnection等实现连接池功能,连接池是供对connection、session、producer的“池”,PoolConnectionFactory的类注释说明的原因:

<b>NOTE:</b> while this implementation does allow the creation of a collection of active consumers,
it does not 'pool' consumers. Pooling makes sense for connections, sessions and producers, which
are expensive to create and can remain idle a minimal cost. Consumers, on the other hand, are usually
just created at startup and left active, handling incoming messages as they come. When a consumer is
complete, it is best to close it rather than return it to a pool for later reuse: this is because,
even if a consumer is idle, ActiveMQ will keep delivering messages to the consumer's prefetch buffer,
where they'll get held until the consumer is active again.

If you are creating a collection of consumers (for example, for multi-threaded message consumption), you
might want to consider using a lower prefetch value for each consumer (e.g. 10 or 20), to ensure that
all messages don't end up going to just one of the consumers. See this FAQ entry for more detail:
http://activemq.apache.org/i-do-not-receive-messages-in-my-second-consumer.html

 1)首先connection、session、producer的创建会消耗大量系统资源;

 2)其次consumer有自己的机制,第二段中url中对一个问题进行了说明,其中讲到consumer的一个特性:consumer会获取全部的消息,接收消息的多少可以根据初始化缓存的大小设置,因此在大量消息发送到消费者时,消费者使用类似统一获取、统一消费的方式处理,“池”没有存在的价值。

2. 实现原理

PoolConnectionFactory

  • “池”的存放

PoolConnection被一个Map对象存放,ConnectionKey作为该map的key,LinkedList作为连接存放的列表,也就是说获取连接时,首先会根据ConnectionKey获取对应的“小连接池”,再从“小连接池”LinkedList中去连接。

  • 工厂类的参数值

maxmunActive:session的最大活跃值,该参数会通过ConnectionPool的createSession方法如入到Session工程类中(apache-common-pool的GenericObjectPoolFactory);

maxConnections:Map的value,LinkedList的大小,即ConnectionPool数量;

idleTimeout:线程超时时间,最后使用时间+idleTimeout<当前时间,连接关闭;

expiryTimeout:回收时间,连接创建时间+expiryTimeout<当前时间,连接关闭;

  • 连接创建流程

1)判断工厂是否stop,如果stop,输出日志并返回null;

2)获取ConnectionKey;

3)根据ConnectionKey获取LinkedList;

4)如果LinkedList的大小==maxConnections,获取LinkedList的第一个连接;

5)校验连接,检验失败:a、创建新连接Connection b、通过连接创建ConnectionPool c、将ConnectionPool注入工厂;

6)将ConnectionPool放入LinkedList中;

其中创建ConnectionPool设计SessionPool的初始化。

3. 样例代码

  • 创建连接
public class MQPoolUtil {

    private static PooledConnection conn;
    
    public static void init() {
        String url = "failover:(tcp://192.168.174.250:61616)?initialReconnectDelay=1000&timeout=3000&startupMaxReconnectAttempts=2";
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(url);
        try {
            PooledConnectionFactory poolFactory = new PooledConnectionFactory(factory);
            conn = (PooledConnection) poolFactory.createConnection();
            conn.start();
            
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
    
    public static void destroy(){
        try {
            if(conn != null) {
                conn.close();
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }

    
    public static PooledConnection getConn() {
    
        return conn;
    }

    
    public static void setConn(PooledConnection conn) {
    
        MQPoolUtil.conn = conn;
    }
}

  • 创建session及producer
public class MQProducer extends Thread {

    public void run() {

        String topic = "MQ.TEST";
        Session session = null;
        MessageProducer producer = null;
        try {
            session = MQPoolUtil.getConn().createSession(false, Session.AUTO_ACKNOWLEDGE);

            Destination destination = session.createTopic(topic);
            
            System.out.println("session info ->" +session);

            producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            TextMessage message = session.createTextMessage("hello message!");
            producer.send(message);
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

当执行多次后,从System.out.println中可以看出,sessionid可能是重复的,即缓存中获取了session。

猜你喜欢

转载自winnie825.iteye.com/blog/1697193