ActiveMQ介绍(二)
来源:互联网 发布:鞍山北国知春房价 编辑:程序博客网 时间:2024/05/16 17:52
3 ActiveMQ
3.1 MessageProducer
异步/同步发送
ActiveMQ支持以同步(sync)方式或者异步(async)方式向broker发送消息。使用何种方式对send方法的延迟有巨大的影响。对于生产者来说,既然延迟是决定吞吐量的重要因素,那么使用异步发送方式会极大地提高系统的性能。
ActiveMQ缺省使用异步传输方式。按照JMS规范,当在事务外发送持久化消息的时候强制使用同步发送方式。在这种情况下,每一次发送都是同步的,而且阻塞到收到broker的应答。这个应答保证了broker已经成功地将消息持久化,而且不会丢失。但是这样做也严重影响了性能。
如果你对系统可以容忍少量的消息丢失,那么可以在事务外发送持久消息的时候,选择使用异步方式。以下是几种不同的配置方式:
方法一,通过建立ActiveMQConnectionFactory时的URL配置,示例如下:
cf = new ActiveMQConnectionFactory("tcp://locahost:61616?jms.useAsyncSend=true");方法二,通过ActiveMQConnectionFactory的方法调用,示例:
((ActiveMQConnectionFactory) connectionFactory).setUseAsyncSend(true);方法三,通过connection的方法调用,示例如下:
((ActiveMQConnection)connection).setUseAsyncSend(true);同步发送消息的Producer会自动使用producer flow control;对于异步发送消息的producer,要使用producerFlowControl,先要为connection配置一个ProducerWindowSize参数,如下:
((ActiveMQConnectionFactory)cf).setProducerWindowSize(1024000);ProducerWindowSize是producer在发送消息的过程中,收到broker对于之前发送消息的确认之前,能够发送消息的最大字节数。
设置了ProducerFlowControl属性时,但broker端的内存使用或者单个Destination的内存使用达到上限时,会对Producer端进行限流。
3.2 MessageConsumer
在ActiveMQ中,异步消费要比同步消费的时延要小,相应更快。这是因为同步消费会把消息放入broker内部的消费队列所致。所以最好采用异步消费,在Consumer上实现MessageListener接口,而不是采用MessageConsumer.receive()方法。
3.3 Transport
ActiveMQ目前支持的transport有:VM Transport、TCP Transport、SSL Transport、Peer Transport、UDP Transport、Multicat Transport、HTTP and HTTPs Transport、Failover Transport、Fanout Transport等。
TCP Transport允许客户端通过TCP socket连接到broker。以下是配置语法:
tcp://hostname:port?transportOptions
这是broker默认使用的transport协议。适用于大部分场合,采用阻塞I/O操作,降低网络延时。
例如:tcp://localhost:61616?trance=false
ActiveMQ同时提供了NIO协议的transport,它的底层也是通过TCP协议实现的。与TCP协议不同的是,它通过SELECT机制来管理多路非阻塞式连接,降低了系统的线程数。提供很好的垂直扩展性。如果一个broker上面的连接过多时,应该采用这种方式来代替TCP Transport协议。配置语法与TCP相同:
nio://hostname:port?transportOptions
说了那么多,下面来一个Java实例:
Producer.java:
import org.apache.activemq.ActiveMQConnectionFactory;import javax.jms.*;import javax.xml.soap.Text;import java.net.ConnectException;/** * Created by niuliguo on 2017/1/12. */public class Producer { private static String uri = "tcp://ip:61616"; private static String user = "xxxx"; private static String password = "xxxx"; private static String subject = "xxxx"; private static boolean transacted = false; private static Connection connection; private static final String message = "bizid=jy_cache_test&role=cache"; public static void main(String[] args){ Destination destination = null; try { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory( user,password,uri); connection = connectionFactory.createConnection(); connection.start(); if ( null == connection ){ System.exit(-1); } Session session = connection.createSession(transacted,Session.AUTO_ACKNOWLEDGE); destination = session.createTopic(subject); MessageProducer producer = session.createProducer(destination); producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); TextMessage textMessage = session.createTextMessage(message); int i = 5; while ( (i--)!=0 ) { producer.send(textMessage); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } catch (JMSException e){ e.printStackTrace(); } finally { try { if ( null != connection ){ connection.close(); } } catch (JMSException e){ e.printStackTrace(); } } }}Consumer.java:
import org.apache.activemq.ActiveMQConnectionFactory;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.jms.*;/** * Created by niuliguo on 2017/1/12. */public class Consumer implements MessageListener,Runnable{ private final Logger logger = LoggerFactory.getLogger(Consumer.class); private Session session; private String uri = "tcp://ip:61616"; private String user = "xxxx"; private String password = "xxxxxx"; private String subject = "xxxxxx"; private boolean transacted = false; public void onMessage(Message message) { TextMessage textMessage = (TextMessage)message; try { String msg = textMessage.getText(); System.out.println(msg); } catch (JMSException e){ e.printStackTrace(); } } public void run() { Connection connection = null; Destination destination = null; MessageConsumer consumer = null; try { ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,uri); connection = connectionFactory.createConnection(); connection.start(); session = connection.createSession(transacted,Session.AUTO_ACKNOWLEDGE); destination = session.createTopic(subject); consumer = session.createConsumer(destination); consumer.setMessageListener(this); } catch ( JMSException e) { e.printStackTrace(); } } public static void main(String[] args){ Consumer consumer = new Consumer(); consumer.run(); }}
Tips:
1.生产者和消费者不要和Broker部署在不同的数据中心,避免网络延迟和不稳定对系统带来的影响。
2.请不要将wireFormat.maxInactivityDuration的设置修改成为小于默认值30000ms,易受网络抖动影响。
3.客户端代码中需要复用connect以及session对象,避免每次生产和消费时都重建对象造成对服务器和客户端的压力。
4.生产者发送速率调优:
>对于数据可靠性要求较低,容忍数据在极端情况下丢失的场景中,使用NON_PERSISTENT
>配置alwaysSyncSend=false,对于"NON_PERSISTENT"(非持久化)消息将使用"异步发送";并可以通过windowSize来调整在异步发送时producer端允许积压的(尚未ACK)的消息的尺寸,该值需要根据客户端的内存进行配置。
>尽量少用消息属性
5.消费者消费速率调优:
>optimizeAcknowledge:consumer批量进行ACK,如果无法接受重复收到消息的情况,不要将其设置为TRUE
>asyncDispatch:异步发送,如果设置为true,broker发送消息不会阻塞,但是如果Queue/Topic中的consumer客户端接收和消费消息的速度很快,可以关闭异步转发来避免线程切换。
6.使用VirtualTopic:
>同一应用内consumer端负载均衡的问题:在一个应用上的持久订阅不能使用多个consumer来共同承担消息处理功能。因为美国都会获取所有消息。queue模式可以解决这个问题,broker端又不能将消息发送到多个应用端。所以,既要发布订阅,又要让消费者分组,,这个功能jms规范本身是没有的。
>统一应用内consumer端failover的问题:由于只能使用单个的持久订阅者,如果这个订阅者出错,则应用就无法处理消息了,系统的健壮性不高
解决方法:
>生产者:对于消息发布者来说,就是一个正常的Topic,名称以VirtualTopic.开头。例如:VirtualTopic.TEST。
>消费者:对于消费接收端来说,是个队列,不同应用里使用不同的前缀作为队列的名称,即可表明自己的身份可实现消费端应用分组。例如Consumer.A.VirtualTopic.TEST,说明它是名称为A的消费端,同理Consumer.B.VitualTopic.TEST说明是一个名称为B的客户端。可以在同一个应用里使用多个consumer消费此queue,则可以实现上面两个功能。又因为不同应用使用的queue名称不同(前缀不同),所以不同的应用中都可以接收到全部的消息。每个客户端相当于一个持久订阅者,而且这个客户端可以使用多个消费者共同来承担消费任务。
向Topic发送消息,从Queue消费消息(消费者集群)。Queue:是Topic的持久订阅者。
创建VirtualTopic.Queue:可以先创建Queue,定义该Queue name为Consumer.<consumer name>.VirtualTopic.<topic name>。
7.ActiveMQ服务器跨机房会存在延时问题,建议使用和客户端在同DC的服务器。
8.非持久性消息:消息全部存在内存中,收发效率会更高,但一旦重启MQ服务,内存中的消息会全部消失,不可以找回。持久性消息,消息首先完成持久化过程(磁盘),会比较耗时,但可以确保消息不丢失。手法效率不如非持久性消息。
Author:忆之独秀
Email:leaguenew@qq.com
注明出处:http://blog.csdn.net/lavorange/article/details/65633981
- ActiveMQ介绍(二)
- ActiveMQ(二)--ActiveMQ基本介绍
- activemq的网络层介绍(二)
- ActiveMQ 介绍(二)之JMS
- ActiveMQ介绍(一)
- ActiveMQ深入浅出(二)——ActiveMQ简单介绍以及安装
- 深入浅出ActiveMQ(二)--ActiveMQ简单介绍以及安装
- ActiveMQ教程(二)
- ActiveMQ笔记(二)
- ActiveMQ集群(二)
- ActiveMq 自学(二)
- ActiveMQ学习(二)
- ActiveMQ基础知识(二)
- 有关ActiveMQ(二)
- JMS(二)--ActiveMQ简单介绍以及安装
- ActiveMQ(二):ActiveMQ的简单入门
- ActiveMQ基本介绍(1)
- ActiveMQ : ActiveMQ入门介绍
- FZU1062(找规律+模拟)
- Android EditText回车不换行
- Java 数据强转 不一定低到高.
- 关于解决子元素继承父元素事件的问题
- LAMP环境准备gcc和gcc++
- ActiveMQ介绍(二)
- fzu 1050 Number lengths
- 简单学习自动化测试框架(selenium)
- Flume中的拦截器(Interceptor)介绍与使用(二)
- reportviewer使用方法
- 冷知识 —— 四大
- 自动化构建工具--gulp中gulpfile的基础配置
- 判断树是否结构对称
- Python的sys.path妙用