ActiveMQ 总结

来源:互联网 发布:二级c语言选择题题库 编辑:程序博客网 时间:2024/05/17 07:08

前端时间系统改造,要使用MQ,开始MQ版本没定。自己就把ActiveMQ,RabbitMQ,RocketMQ的入门都粗略的学习一遍。现在老大已决定在给客户演示的时候用RocketMQ,然而上线的时候却要用非开源的,例如某东的JMQ,某Q的CMQ。现在版本已出,测试通过,无聊中,顺便整理一下前段时间自己的学习成果。

ActiveMQ入门

http://www.cnblogs.com/zhuxiaojie/p/5564187.html

1JMS

1.1JMS规范

连接工厂:连接工厂是客户用来创建连接的对象。

连接:封装了客户与JMS提供者之间的一个虚拟连接。

会话:生产和消费消息的一个单线程上下文。

目的地:客户用来指定生产消息的目标,和消费消息的数据来源。

消息生产者:由会话创建的一个对象,用于把消息发送到一个目的地。

消息发送者:由会话创建的一个对象,用于接收发送到目的地的对象。

消息:消息包含了消息头,消息属性,消息体。

1.2JMS的可靠性

ACK机制:只有在被确认之后,才能被认为成功的消费了。

持久性:ActiveMQ的持久性可以用,data logs,kaha ,jdbc

消息过期:

临时目的地:

持久订阅:

本地事物:

2.ActiveMQ

2.1ActiveMQ的通讯方式

2.2 ActiveMQ特色

2.2.1 独占消费

queue中的消息是按照顺序被分发到consumers中的,而独占消费就是在很多consumer种只选择一个consumer来处理queue中的所有消息。

2.2.2  消息分组

独占消费的增强,也就是保证了消息属性相同的JMSGroup ID的消息会发送到相同的consumer

2.2.3 JMS selectors

     消息过滤器,基于SQL语法。

2.2.4 Pending Message Limit Strategy

首先简要介绍一下prefetch机制。ActiveMQ通过prefetch机制来提高性能,这意味这客户端的内存里可能会缓存一定数量的消息。缓存消息的数量由prefetch limit来控制。当某个

consumer的prefetch buffer已经达到上限,那么broker不会再向consumer分发消息,直到consumer向broker发送消息的确认。

慢消费者会在非持久的topics上导致问题:一旦消息积压起来,会导致broker把大量消息保存在内存中,broker也会因此而变慢。未来ActiveMQ可能会实现磁盘缓存,但是这也还

是会存在性能问题。目前ActiveMQ使用Pending Message Limit Strategy来解决这个问题。除了prefetch buffer之外,你还要配置缓存消息的上限,超过这个上限后,新消息到

来时会丢弃旧消息。通过在配置文件的destination map中配置PendingMessageLimitStrategy,可以为不用的topic namespace配置不同的策略。目前有以下两种:
• ConstantP

endingMessageLimitStrategy。这个策略使用常量限制。 例如:<constantPendingMessageLimitStrategy limit="50"/>
• PrefetchRatePendingMessageLimitStrategy。这个

策略使用prefetch size的倍数限制。 例如:<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>
在以上两种方式中,如果设置0意味着除了prefetch之外不再缓存消

息;如果设置-1意味着禁止丢弃消息。 此外,你还可以配置消息的丢弃策略,目前有以下两种:
• oldestMessageEvictionStrategy。这个策略丢弃最旧的消息。
• oldestMessag

eWithLowestPriorityEvictionStrategy。这个策略丢弃最旧的,而且具有最低优先级的消息。

2.2.5 虚拟队列

topic模式的增强。

它允许用一个虚拟的destination 代表多个destinations。例如你可以通过composite destinations在一个操作中同时向12queue发送消息。

2.2.6 镜像队列

每个queue中的消息只能被一个consumer消费。然而,有时候你可能希望能够监视生产者和消费者之间的消息流。你可以通过使用Virtual Destinations 来建立一个virtual queue 来把消息转发到多个queues中。但是 为系统中每个queue都进行如此的配置可能会很麻烦。 ActiveMQ支持Mirrored QueuesBroker会把发送到某个que

ue的所有消息转发到一个名称类似的topic,因此监控程序可以订阅这个mirrored queue topic。为了启用Mirrored Queues,首先要将BrokerServiceuseMirroredQue

ues属性设置成true,然后可以通过destinationInterceptors设置其它属性,如mirror topic的前缀,缺省是"VirtualTopic.Mirror."

2.2.7 支持同步异步发送

2.2.8 分发策略

2.2.9 消息的游标

http://blog.csdn.net/neareast/article/details/7582947

2.2.10 批量确认

------------个人测试代码

package com.czy.demo.ActiveDemo.helloworld;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import javax.jms.Topic;import org.apache.activemq.ActiveMQConnectionFactory;import org.junit.After;import org.junit.Before;import org.junit.Test;public class Receiver {Connection connection = null;Session session = null;MessageConsumer consumer = null;@Beforepublic void before() throws JMSException {// 1.创建ConnectionFactory工厂ConnectionFactory factory = new ActiveMQConnectionFactory("czy", "czy", "tcp://localhost:61616");// 2.创建Connectionconnection = factory.createConnection();connection.setClientID("11");// 持久化订阅要设置ID, //生产者创建的消息类型必须为持久化的connection.start();}@Testpublic void testQueue() throws JMSException {// 3.创建section// 第一个参数,是否开启事物 第二个参数 ACK的类型session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 4.创建destinationDestination destination = session.createQueue("queue1");consumer = session.createConsumer(destination);receive();/* * 分别运行receive和receive2的testQueue方法 发现俩个ActiveMQ会把队列中的消息依次发送给消费者,直到发送完毕 * 可能出现的结果 receive接受到消息0,2,4 receive2接受到结果1,3 */}@Testpublic void testTopic() throws JMSException {// 3.创建sectionsession = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 4.创建destinationDestination destination = session.createTopic("topic1");consumer = session.createConsumer(destination);receive();/* * 分别运行receive和receive2的testTopic方法 发现俩个ActiveMQ会把队列中的消息都发送给激活状态下的消费者 * 出现的结果 receive接受到消息0,1,2,3,4 receive2接受到结果0,1,2,3,4 * 如果消费者后运行,先运行生产者,消费者是接受不到消费的 */}@Testpublic void testAckNowledge() throws JMSException {// 3.创建section// Session.AUTO_ACKNOWLEDGE 自动提交// Session.CLIENT_ACKNOWLEDGE 客户端手动确认// Session.DUPS_OK_ACKNOWLEDGE 自动批量提交// Session.SESSION_TRANSACTED 在事物的环境中 这种ACK类型,前面的参数要为truesession = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);// ssession=connection.createSession(Boolean.TRUE,// Session.SESSION_TRANSACTED);// 4.创建destinationDestination destination = session.createQueue("queue1");consumer = session.createConsumer(destination);// receiveWithACK(false);// receiveWithACK(true);// receiveWithTransaction(null);// receiveWithTransaction(false);// receiveWithTransaction(true);/* * 分别先用前三章种ACK类型,创建session,然后运行receiveWithACK 发现自动提交和自动批量提交,表现一致, * 都是无论是否手动ACK,接受到的消息都会从未消费队列中删除 而手动提交只有提交之后才会在未消费队列中删除 * 用事物类型Ack创建session,然后运行receiveWithTransaction,只有显示提交才会从未消费队列中删除 * 回滚,或者不处理事物都不会从未消费队列中删除 */}@Testpublic void testDurableSubscriber() throws JMSException {// 3.创建sessionsession = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// ssession=connection.createSession(Boolean.TRUE, Session.SESSION_TRANSACTED);// 4.创建destinationTopic topic = session.createTopic("topic1");consumer = session.createDurableSubscriber(topic, "11");receive();//先运行生产者生产消息,在运行消费者仍然可以接受到消费者离线前的消息//而且如果是客户端,手动ACK,俩个持久化的订阅不会相互影响//比如11,手动确认了,22仍然可以接受到消息,直到22也手动确认,事物也是一样}@Testpublic void testExclusive() throws JMSException{session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);Destination destination = session.createQueue("queue1?consumer.exclusive=true");consumer = session.createConsumer(destination);receive();/** * 测试结果,会从多个consumers中挑选一个consumer来处理queue中所有的消息, * 从而保证了消息的有序处理,而不是分发到各个消费者 */}@Testpublic void testSelecor() throws JMSException{// 3.创建section// 第一个参数,是否开启事物 第二个参数 ACK的类型session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 4.创建destinationDestination destination = session.createQueue("queue1");consumer = session.createConsumer(destination,"number>=2");receive();/** * 选择器,只会选择符合条件的消息, * 制定注意的是表达式中的属性不会进行自动类型转换 */}public void receiveWithTransaction(Boolean isCommit) throws JMSException {receive(null, isCommit);}public void receiveWithACK(Boolean isAck) throws JMSException {receive(isAck, null);}public void receive() throws JMSException {receive(null, null);}public void receive(Boolean isAck, Boolean isCommit) throws JMSException {// 6.消费消息内容while (true) {TextMessage message = (TextMessage) consumer.receive();System.out.println("");if (message == null)break;System.out.println("接受的内容" + message.getText());if (isAck!=null && isAck == true) {message.acknowledge();}if (isCommit == null) {} else if (isCommit == true) {session.commit();} else if (isCommit == false) {session.rollback();}}}@Afterpublic void close() throws JMSException {if (connection != null) {connection.close();}}}
package com.czy.demo.ActiveDemo.helloworld;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import javax.jms.Topic;import org.apache.activemq.ActiveMQConnectionFactory;import org.junit.After;import org.junit.Before;import org.junit.Test;public class Receiver2 {Connection connection = null;Session session = null;MessageConsumer consumer = null;@Beforepublic void before() throws JMSException {// 1.创建ConnectionFactory工厂ConnectionFactory factory = new ActiveMQConnectionFactory("czy", "czy", "tcp://localhost:61616");// 2.创建Connectionconnection = factory.createConnection();connection.setClientID("22");// 持久化订阅要设置ID, //生产者创建的消息类型必须为持久化的connection.start();}@Testpublic void testQueue() throws JMSException {// 3.创建section// 第一个参数,是否开启事物 第二个参数 ACK的类型session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 4.创建destinationDestination destination = session.createQueue("queue1");consumer = session.createConsumer(destination);receive();/* * 分别运行receive和receive2的testQueue方法 发现俩个ActiveMQ会把队列中的消息依次发送给消费者,直到发送完毕 * 可能出现的结果 receive接受到消息0,2,4 receive2接受到结果1,3 */}@Testpublic void testTopic() throws JMSException {// 3.创建sectionsession = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 4.创建destinationDestination destination = session.createTopic("topic1");consumer = session.createConsumer(destination);receive();/* * 分别运行receive和receive2的testTopic方法 发现俩个ActiveMQ会把队列中的消息都发送给激活状态下的消费者 * 出现的结果 receive接受到消息0,1,2,3,4 receive2接受到结果0,1,2,3,4 * 如果消费者后运行,先运行生产者,消费者是接受不到消费的 */}@Testpublic void testAckNowledge() throws JMSException {// 3.创建section// Session.AUTO_ACKNOWLEDGE 自动提交// Session.CLIENT_ACKNOWLEDGE 客户端手动确认// Session.DUPS_OK_ACKNOWLEDGE 自动批量提交// Session.SESSION_TRANSACTED 在事物的环境中 这种ACK类型,前面的参数要为truesession = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);// ssession=connection.createSession(Boolean.TRUE,// Session.SESSION_TRANSACTED);// 4.创建destinationDestination destination = session.createQueue("queue1");consumer = session.createConsumer(destination);// receiveWithACK(false);// receiveWithACK(true);// receiveWithTransaction(null);// receiveWithTransaction(false);// receiveWithTransaction(true);/* * 分别先用前三章种ACK类型,创建session,然后运行receiveWithACK 发现自动提交和自动批量提交,表现一致, * 都是无论是否手动ACK,接受到的消息都会从未消费队列中删除 而手动提交只有提交之后才会在未消费队列中删除 * 用事物类型Ack创建session,然后运行receiveWithTransaction,只有显示提交才会从未消费队列中删除 * 回滚,或者不处理事物都不会从未消费队列中删除 */}@Testpublic void testExclusive() throws JMSException{session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);Destination destination = session.createQueue("queue1?consumer.exclusive=true");consumer = session.createConsumer(destination);receive();}@Testpublic void testDurableSubscriber() throws JMSException {// 3.创建sessionsession = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// ssession=connection.createSession(Boolean.TRUE, Session.SESSION_TRANSACTED);// 4.创建destinationTopic topic = session.createTopic("topic1");consumer = session.createDurableSubscriber(topic, "22");receive();//先运行生产者生产消息,在运行消费者仍然可以接受到消费者离线前的消息//而且如果是客户端,手动ACK,俩个持久化的订阅不会相互影响//比如11,手动确认了,22仍然可以接受到消息,直到22也手动确认,事物也是一样}public void receiveWithTransaction(Boolean isCommit) throws JMSException {receive(null, isCommit);}public void receiveWithACK(Boolean isAck) throws JMSException {receive(isAck, null);}public void receive() throws JMSException {receive(null, null);}public void receive(Boolean isAck, Boolean isCommit) throws JMSException {// 6.消费消息内容while (true) {TextMessage message = (TextMessage) consumer.receive();System.out.println("");if (message == null)break;System.out.println("接受的内容" + message.getText());if (isAck!=null && isAck == true) {message.acknowledge();}if (isCommit == null) {} else if (isCommit == true) {session.commit();} else if (isCommit == false) {session.rollback();}}}@Afterpublic void close() throws JMSException {if (connection != null) {connection.close();}}}


package com.czy.demo.ActiveDemo.helloworld;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.DeliveryMode;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageProducer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnectionFactory;import org.junit.After;import org.junit.Before;import org.junit.Test;/** * ActiveMQ 版本 5.14.2 *  * @author chenzhiyuan * */public class Sender {Session session = null;MessageProducer producer = null;Connection connection = null;@Beforepublic void before() throws JMSException {// 1.创建ConnectionFactory工厂ConnectionFactory factory = new ActiveMQConnectionFactory("czy", "czy", "tcp://localhost:61616");// 2.创建Connectionconnection = factory.createConnection();connection.start();}@Testpublic void testQueue() throws JMSException {session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 6.发送消息send();// 测试结果在消费者里描述}@Testpublic void testTopic() throws JMSException {session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createTopic("topic1");// 5.创建生产者producer = session.createProducer(des);// 6.发送消息send();// 测试结果在消费者里描述}@Testpublic void testTransaction() throws JMSException {// 3.创建session true开启事物,AUTO_ACKNOWLEDGE 自动提交// 这俩种方式创建Session,不影响下面发送消息的结果// session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);session = connection.createSession(true, Session.SESSION_TRANSACTED);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 6.生产消息// sendWithTransaction(true);// sendWithTransaction(false);// sendWithTransaction(null);/* * 依次取消上面注释,分别执行,得到测试结果 在开启事物的时候,只有显示提交时才会有消息进入队列 */}@Testpublic void testNoTransaction() throws JMSException {// 3.创建session false不开启事物,AUTO_ACKNOWLEDGE 自动提交session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 这样创建session会报错// session = connection.createSession(false,// Session.SESSION_TRANSACTED);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 6.生产消息sendWithTransaction(true);// sendWithTransaction(false);// sendWithTransaction(null);/* * 依次取消上面注释,分别执行,得到测试结果 在未开启事物的时候,显示提交或回滚会报错, 但是提交或者回滚前生产的那条记录,会入队成功。 */}@Testpublic void testAcknowledgeType() throws JMSException {// 3.创建session false不开启事物,CLIENT_ACKNOWLEDGE 自动提交// Session.AUTO_ACKNOWLEDGE 自动提交// Session.CLIENT_ACKNOWLEDGE 客户端手动确认// Session.DUPS_OK_ACKNOWLEDGE 自动批量提交// Session.SESSION_TRANSACTED 在事物的环境中session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// SendWithAck(false);// SendWithAck(true);/* * 测试结果 无论哪种ACK类型,无论是否显示的进行却仍,都会入队成功, ACK的类型不影响生产者生产消息,或者说ACK机制就是针对客户端的 */}@Testpublic void testNonPersistent() throws JMSException {session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 非持久化// producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);producer.setDeliveryMode(DeliveryMode.PERSISTENT);// 发送消息send();/** * 测试结果 如果没有设置持久化,重启ActiveServer消息会丢失, 消费者接受不到消息, * 如果设置了持久化,重启之后消费者仍然能接受到消息 默认的持久化策略是kahadb,当然mysql,oracle等传统关系型数据库也可以 * 想不到什么情况下会有关系型数据库当成持久化策略,不演示 *  */}@Testpublic void testMessageGroupId() throws JMSException {session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 6.发送消息for (int i = 0; i < 5; i++) {TextMessage message = session.createTextMessage();message.setText("我是消息内容i=" + i);message.setStringProperty("JMSXGroupID", "groupId11");producer.send(message);/* * 跟所有的消息都由唯一的consumer处理不同, JMS 消息属性JMSXGroupID 被用来区分message group。 * Message Groups特性保证所有具有相同JMSXGroupID 的消息 * 会被分发到相同的consumer(只要这个consumer保持active)。 另外一方面,Message * Groups特性也是一种负载均衡的机制。 * 在一个消息被分发到consumer之前,broker首先检查消息JMSXGroupID属性。 如果存在,那么broker * 会检查是否有某个consumer拥有这个message group。 * 如果没有,那么broker会选择一个consumer,并将它关联到这个message group。 * 此后,这个consumer会接收这个message group的所有消息,直到Consumer被关闭。 */ }}@Testpublic void testMessageSelector() throws JMSException {session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1");// 5.创建生产者producer = session.createProducer(des);// 6.发送消息for (int i = 0; i < 5; i++) {TextMessage message = session.createTextMessage();message.setIntProperty("number",i);message.setText("我是消息内容i=" + i);System.out.println("这是生产者:" + message.getText());producer.send(message);}}@Testpublic void testCompositeDestination() throws JMSException {session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);// 4.创建目的地Destination des = session.createQueue("queue1,queue2,queue3,queue4,queue5");// 5.创建生产者producer = session.createProducer(des);// 6.发送消息send();//CompositeDestination它允许用一个虚拟的destination 代表多个destinations。//例如你可以通过composite destinations在一个操作中同时向12个queue发送消息。//在composite destinations中,多个destination之间采用","分割//如果你希望使用不同类型的destination,那么需要加上前缀如queue:// 或topic://}public void send() throws JMSException {send(null, false);}public void sendWithTransaction(Boolean isCommit) throws JMSException {send(isCommit, false);}public void SendWithAck(Boolean isAck) throws JMSException {send(null, isAck);}public void send(Boolean isCommit, Boolean isAck) throws JMSException {// 发送消息for (int i = 0; i < 5; i++) {TextMessage message = session.createTextMessage();message.setText("我是消息内容i=" + i);producer.send(message);if (isAck == true) {message.acknowledge();}if (isCommit == null) {System.out.println("这是生产者:" + message.getText());} else if (isCommit == true) {session.commit();System.out.println("commit---这是生产者:" + message.getText());} else if (isCommit == false) {session.rollback();System.out.println("rollback---这是生产者:" + message.getText());}}}@Afterpublic void after() throws JMSException {if (connection != null) {connection.close();}}}



原创粉丝点击