一.  修改访问账号、密码

 在activemq.xml文件中修改如下:

<plugins>
            <simpleAuthenticationPlugin>
                <users>
                    <authenticationUser username="root" password="123" groups="users,admins"/>
                </users>
            </simpleAuthenticationPlugin>
        </plugins>

修改username和password,group表示角色名,我这里设置了自带的角色users和admins。

二. 故障转移

failover:(tcp://localhost:61616,tcp://localhost:61617,tcp://localhost:61618)?randomize=false&timeout=5000

我这里设置了randomize为false,表示当主服务器不可用时,从右边的从服务器列表选举一个作为新的主服务器。 

详细配置,可参考官网: http://activemq.apache.org/failover-transport-reference.html

三. 事务

  • Session.SESSION_TRANSACTED:事务,使用session.commit();提交
  • Session.AUTO_ACKNOWLEDGE:在消费者receive或者MessageListener成功返回后,自动提交 
  • Session.CLIENT_ACKNOWLEDGE:使用message.acknowledge()手动提交,只要被消费的消息,都会被一次性提交。
  • Session.OPS_OK_ACKNOWLEDGE:批量提交,允许有重复的消息,重复的消息的消息头中的JMSRedelivered被设置为true

关于第一种的Session在生产者中的使用:

connection.createSession(true, Session.SESSION_TRANSACTED); 第一个参数设置为true,表示使用事务

for (int i = 0; i < 10000; i++) {
				String messageBody = "This is NO." + i + " message";
				TextMessage textMessage = session.createTextMessage(messageBody);
				publisher.send(textMessage);
				if (i == 5000)
					session.commit();
			}

然后访问 localhost:8161,查看入队的消息数,结果为5001。说明提交了从0到5000的消息。

再来看下session.rollback()的用法。

try {
             .....................
             for (int i = 0; i < 10000; i++) {
                 String messageBody = "This is NO." + i + " message";                System.out.println(1 / 0);
                 TextMessage textMessage = session.createTextMessage(messageBody);
                 publisher.send(textMessage);
                 if (i == 5000)
                     session.commit();
             }
         } catch (Exception e) {
             try {
                 Objects.requireNonNull(session).rollback();
             } catch (JMSException e) {
                 e.printStackTrace();
             }
         }

结果一个信息都没有发送成功。入队失败。

再来看在消费者中的使用:

   

session = connection.createSession(true, TopicSession.SESSION_TRANSACTED);
             destination = session.createTopic(destinationName);
             subscriber = session.createSubscriber(destination);
             while (true) {
                 Message message = subscriber.receive();
                 if (message instanceof TextMessage) {
                     TextMessage textMessage = (TextMessage) message;
                     System.out.println(textMessage.getText());
                 }
             }

事务不提交试下,能输出信息,消息能出队。说明这个Session用法对于消费者没用。

再看下回滚对于消费者的影响:

while (true) {
                 Message message = subscriber.receive();
                 if (message instanceof TextMessage) {
                     TextMessage textMessage = (TextMessage) message;
                     System.out.println(textMessage);
                     System.out.println(1 / 0);
                     session.commit();
                 }
             }
             
         } catch (Exception e) {
             try {
                 Objects.requireNonNull(session).rollback();
             } catch (JMSException e) {
                 e.printStackTrace();
             }
         }

结果是消费者无法继续获得消息,也无法出队。

 

总结:Session.SESSION_TRANSACTED 对于生产者而言,session.commit()控制了消息的入队,session.rollback()会导致消息无法入队。 对于消费者而言,session.commit()不影响消费者获得消息,也不影响消息的出队,但是session.rollback()会导致后续的消息无法出队,同时中断消费者获得消息。


 Session.AUTO_ACKNOWLEDGE 对于生产者而言,发送消息中如果遇到异常,会中断消息的入队。比如第50条发生异常,并不影响前49条的入队。

对于消费者而言。自动获取消息,消息正常出队。但是遇到异常,消费者中断获取消息,并且后续的消息无法出队。


Session.CLIENT_ACKNOWLEDGE 生产者情况同上。即使不加acknowledge,也会入队。发送消息中如果遇到异常,会中断消息的入队。消费者acknowledge影响消息的出队。但不影响获得消息。但是遇到异常,消费者中断获取消息,并且后续的消息无法出队。

四. 优化确认

用于单个批次操作中确认一系列消息。 

<property name="optimizeAcknowledge" value="true"/>
<property name="optimizeAcknowledgeTimeOut" value="300"/>

 optimizeAcknowlede:默认是false,可设置为true,提高吞吐量

 optimizeAcknowledgeTimeOut :确认的超时时间,默认是300ms,0表示禁用