这次真的忽略了一些ActiveMQ内心的娇艳
好久没总结了,内心有点空虚了,所以今天主要给园里的朋友们分享一点儿这几天使用ActiveMQ过程中踩过的小坑,虽然说这东西简单易用,代码几行配置也就几行,问题不大但是后果有点严重,所以就要必要总结一下了。
首先ActiveMQ有俩种消息队列模式:点对点和发布订阅,这俩种都有不可替代的应用场景,前者适用于消息唯一传递的业务,后者适用于分布式环境下进行多面数据同步的操作。
其次一些关于它的官方简介和安装步骤我就不占博客园数据库的内存了,写了也没啥鸟用,用烂的朋友想要提取点儿精华,没接触过的朋友请先安装一个玩玩点对点和发布订阅模式吧(http://www.cnblogs.com/1315925303zxz/p/6377551.html),理解一下这俩种机制的区别和出现消息临界值时的特性,我下面也放一些我前期用于测试的Demo,其中总结了一些他们二者的主要区别,都是实战中必须要考虑的因素可以参考:
假设:存在一个消息生产者、多个消费者,分别在点对点和发布订阅模式下进行消息获取,当出现消息临界值的时候都有什么现象?这些需要朋友你自己体会,我能做的只有送上代码供各位测试了。
消息生产者
 public class ProducerDemo2 {
     private static Random r = new Random();
     public static void main(String[] args) {
         ConnectionFactory connectionFactory; // 连接工厂
         Connection connection = null; // 连接
         Session session; // 会话 接受或者发送消息的线程
         Destination destination; // 消息的目的地
         MessageProducer messageProducer;//消息生产者
         // 实例化连接工厂
         connectionFactory = new ActiveMQConnectionFactory("admin", "admin", "tcp://10.0.40.73:61616");    //用户名、密码、连接地址
         try {
             // 通过连接工厂获取连接
             connection = connectionFactory.createConnection();
             // 启动连接
             connection.start();
             // 创建session
             session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);        //true:支持事务    false:不支持事务
             // 创建/选择一个消息队列
             destination = session.createQueue("BMW");    //点对点
             //destination = session.createTopic("ToyotaYQ");    //发布订阅
             //创建消息生产者
             messageProducer = session.createProducer(destination);
             //创建一条文本消息
             int num = r.nextInt(100);
             TextMessage message = session.createTextMessage("ActiveMQ 生产者2发送消息"+num);
             System.out.println("生产者2发送消息:"+num);
             //通过消息生产者发出消息
             messageProducer.send(message);
             //提交
             session.commit();
         } catch (JMSException e) {
             e.printStackTrace();
         }
     }
 }
消息消费者(可以copy多个进行消息争抢测试)
 public class ConsumerDemo2 {
     // private static final String USERNAME =
     // ActiveMQConnection.DEFAULT_USER;//默认连接用户名(amdin)
     // private static final String PASSWORD =
     // ActiveMQConnection.DEFAULT_PASSWORD;//默认连接密码(admin)
     // private static final String BROKEURL =
     // ActiveMQConnection.DEFAULT_BROKER_URL;//默认连接地址(tcp://localhost:61616)
     public static void main(String[] args) {
         ConnectionFactory connectionFactory; // 连接工厂
         Connection connection = null; // 连接
         Session session; // 会话 接受或者发送消息的线程
         Destination destination; // 消息的目的地
         MessageConsumer messageConsumer; // 消息的消费者
         // 实例化连接工厂
         connectionFactory = new ActiveMQConnectionFactory("admin", "admin", "tcp://10.0.40.73:61616");    //用户名、密码、连接地址
         try {
             // 通过连接工厂获取连接
             connection = connectionFactory.createConnection();
             // 启动连接
             connection.start();
             // 创建session
             session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
             // 创建/选择一个消息队列
             destination = session.createQueue("BMW");            //点对点模式
             //destination = session.createTopic("ToyotaYQ");    //发布订阅模式
             // 创建消息消费者
             messageConsumer = session.createConsumer(destination);
             while (true) {
                  //设置消费者接收消息的时间(3s)
                 TextMessage textMessage = (TextMessage)messageConsumer.receive(3000);
                 if(textMessage == null){
                     System.out.println("没有消息");
                 }else{
                     System.out.println(textMessage.getText());
                     //System.exit(0);
                 }
             }
         } catch (JMSException e) {
             e.printStackTrace();
         }
     }
 }
注意事项:
1、生产者发送消息时必须支持事务,就是创建消息会话的时候设置为true,否则会出现“javax.jms.IllegalStateException: Not a transacted session”异常。消费者可以不支持。
2、点对点模式下,同一时刻只能有一个消费者从队列中获取消息内容,如果存在多个消费者,则会出现消息争抢现象直到消息全部抢完,处于阻塞状态,如果再有消息被放进来时,接着会进行争抢,但是只会有一个消费者获取到消息,不会出现多个消费者抢到消息的情况。
3、点对点模式下,生产者发送消息时,消费者可以处于离线状态,当消费者再次运行时可以接收到历史消息;但是在发布订阅模式下,消费者必须处于运行状态获取消息,历史消息也是不会被获取到的。
实战上线后踩过的坑以及解决方案:
1、用户订单入库成功后发送到MQ中的订单消息丢失,出现处理订单遗漏的情况?
解决方案1:打开消息持久开关。
因为Activemq支持两种消息传送模式:
PERSISTENT (持久消息)该模式是activemq默认的传送方式,此模式下可以保证消息只会被成功传送一次和成功使用一次,消息具有可靠性。在消息传递到目标消费者,在消费者没有成功应答前,消息不会丢失。所以很自然的,需要一个地方来持久性存储。如果消息消费者在进行消费过程发生失败,则消息会被再次投递;
NON_PERSISTENT(非持久消息)该模式适用于消息不重要的,可以接受消息丢失的哪一类消息,这种消息只会被投递一次,消息不会在持久性存储中存储,也不会保证消息丢失后的重新投递。
与spring整合使用ActiveMQ配置文件如下:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory"/>
<!-- deliveryMode, priority, timeToLive 的开关,要生效,必须配置为true,默认false-->
<property name="explicitQosEnabled" value="true" />
<!-- 【发送模式 DeliveryMode.NON_PERSISTENT=1:非持久 ; DeliveryMode.PERSISTENT=2:持久】-->
<property name="deliveryMode" value="2" />
</bean>
解决方案2:设置消息重发机制。
ActiveMQ针对消息丢失情况提供了消息重发机制,假设消息发送失败,为了解决这一尴尬局面,我们可以在实际项目中配置消息重发机制,以防万一。
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.136.139:61616"/>
<property name="redeliveryPolicy" ref="activeMQRedeliveryPolicy" /> <!-- 引用重发机制 -->
</bean> <!-- ActiveMQ消息发送失败后的重发机制 -->
<bean id="activeMQRedeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<!--是否在每次尝试重新发送失败后,增长这个等待时间 -->
<property name="useExponentialBackOff" value="true"></property>
<!--重发次数,默认为6次 这里设置为1次 -->
<property name="maximumRedeliveries" value="1"></property>
<!--重发时间间隔,默认为1秒 -->
<property name="initialRedeliveryDelay" value="1000"></property>
<!--第一次失败后重新发送之前等待500毫秒,第二次失败再等待500 * 2毫秒,这里的2就是value -->
<property name="backOffMultiplier" value="2"></property>
<!--最大传送延迟,只在useExponentialBackOff为true时有效(V5.5),假设首次重连间隔为10ms,倍数为2,那么第
二次重连时间间隔为 20ms,第三次重连时间间隔为40ms,当重连时间间隔大的最大重连时间间隔时,以后每次重连时间间隔都为最大重连时间间隔。 -->
<property name="maximumRedeliveryDelay" value="1000"></property>
</bean>
前天任务调度服务上线后,出现消息丢失的情况,根据以上解决方案是否能够根治这种情况,本人也是不太能够保证,希望稍后能在留言区得到各位老兄的帮助。
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan
这次真的忽略了一些ActiveMQ内心的娇艳的更多相关文章
- python爬虫10 | 网站维护人员:真的求求你们了,不要再来爬取了!!
		
今天 小帅b想给大家讲一个小明的小故事 ... 话说 在很久很久以前 小明不小心发现了一个叫做 学习python的正确姿势 的公众号 从此一发不可收拾 看到什么网站都想爬取 有一天 小明发现了一个小黄 ...
 - Red Hat 4.4.7-4上安装glances填大大大坑实录,我的内心是崩溃的!!!
		
今天的任务是在公司的一台压力测试机上安装一个性能监控工具:glances 因为以前我已经多次安装和使用这个工具,我大意的以为整个过程是这样的: 分分钟搞定完事 然而 我们公司的服务器版本实在是太老了, ...
 - Spring事务失效的 8 大原因,这次可以吊打面试官了!
		
今天再来一篇<吊打面试官>系列,这次真的要吊打了,哈哈!(看往期吊打系列请在后台回复:吊打,我会陆续更新--) 前几天栈长不是发了一篇文章,里面有一个关于事务失效的问题: 用 Spring ...
 - 一个粗心的Bug,JSON格式不规范导致AJAX错误
		
一.事件回放 今天工作时碰到了一个奇怪的问题,这个问题很早很早以前也碰到过,不过没想到过这么久了竟然又栽在这里. 当时正在联调一个项目,由于后端没有提供数据接口,于是我直接本地建立了一个 json ...
 - FZU 1018 枚举dp
		
题意 给出一个数字组成的立方体 在其中选取一个体 使这个体中的数字之和最小 不可以不选 fzu的题目分类动态规划里面不是按难度排得 是按照题号..记得以前做题碰到过算 矩阵里面求子矩阵的最大和的 不会 ...
 - 关于css3的自定义字体
		
css3的@font-face属性打破了中文页面字体一成不变的格局,但今天本菜在用的时候并不那么爽.开始各种引用外部ttf文件失败.下了300M+的字体文件,苦逼的试了一下午.终于有一个ttf引用成功 ...
 - 关于Try/Catch 代码块
		
应当放在Try/Catch 代码块中的常见任务包括连接到一个数据库或与其交互.处理文件.调用Web 服务. 老实说,我这人很少有打破沙锅问到底的精神.不过昨晚听一技术人员跟他的项目经理说要在程序中使用 ...
 - Ubuntu 12.04 Openstack Essex 安装(单节点)
		
这是陈沙克一篇非常好的博文,当时在进行openstack排错的时候,多亏了这篇文章里面有些内容 帮我找到了问题的所在: 原文:http://www.chenshake.com/ubuntu-12-04 ...
 - Bittersweet——NOIP2018 游记
		
p { font-size: 16px; line-height: 1.5em; } blockquote { font-family: 'Times New Roman', 楷体; text-ali ...
 
随机推荐
- 关于python安装一些包时出现的错误解决方法
			
1.关于wordcloud的安装 --win10,py3.6环境下安装总是出现安装错误,解决方法,下载wordcloud的wheel文件,进行安装. 详情参考:https://github.com/a ...
 - (@WhiteTaken)设计模式学习——观察者模式
			
忙里抽闲,继续学习设计模式,作为自己的读书笔记,这次介绍Java下实现的观察者模式. 观察模式需要了解的三个概念: 被观察者:被观察的对象,发生变化会通知观察者集合(存放观察者的容器) 观察者:有up ...
 - 微信公众号第三方 推送component_verify_ticket协议
			
整了一天,终于弄明白了 component_verify_ticket 怎么获取的了.在此先批一下微信公众号平台,文档又没写清楚,又没有客服,想搞哪样哈! 好,回归正题. 第一,先通过开发者资质认证, ...
 - Taffy自动化测试框架简介
			
Taffy Taffy是基于nosetests的自动化测试框架. Taffy主要用来测试后台服务(包括且不限于Http, Dubbo/hessian, Webservice, Socket等类型接口) ...
 - JAVA 编码解码
			
涉及编码的地方一般都在从字符到字节或是从字节到字符间的转换上 1.在IO中存在的编码,主要是 FileOutputStream 和 FileInputStream,在使用时需要指定字符集,而不是使用系 ...
 - 聊聊Java中的反射(一)
			
本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 反射reflection主要为了动态操作Java代码,它的主要功能体现在Java提供的refl ...
 - 详解 $().css('width')和$().width()的区别
			
在本次项目开发中,经常用jquery获取高度和宽度并且动态加载,有时候用$().css('width')或$().width()这两个方法获取宽度并设置,但是有时候出现获取不到的情况,查阅资料后发现他 ...
 - 【深度学习系列】手写数字识别卷积神经--卷积神经网络CNN原理详解(一)
			
上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...
 - A - Wrestling Match HDU - 5971
			
Nowadays, at least one wrestling match is held every year in our country. There are a lot of people ...
 - Be the Winner
			
Be the Winner Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...