好久没总结了,内心有点空虚了,所以今天主要给园里的朋友们分享一点儿这几天使用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内心的娇艳的更多相关文章

  1. python爬虫10 | 网站维护人员:真的求求你们了,不要再来爬取了!!

    今天 小帅b想给大家讲一个小明的小故事 ... 话说 在很久很久以前 小明不小心发现了一个叫做 学习python的正确姿势 的公众号 从此一发不可收拾 看到什么网站都想爬取 有一天 小明发现了一个小黄 ...

  2. Red Hat 4.4.7-4上安装glances填大大大坑实录,我的内心是崩溃的!!!

    今天的任务是在公司的一台压力测试机上安装一个性能监控工具:glances 因为以前我已经多次安装和使用这个工具,我大意的以为整个过程是这样的: 分分钟搞定完事 然而 我们公司的服务器版本实在是太老了, ...

  3. Spring事务失效的 8 大原因,这次可以吊打面试官了!

    今天再来一篇<吊打面试官>系列,这次真的要吊打了,哈哈!(看往期吊打系列请在后台回复:吊打,我会陆续更新--) 前几天栈长不是发了一篇文章,里面有一个关于事务失效的问题: 用 Spring ...

  4. 一个粗心的Bug,JSON格式不规范导致AJAX错误

    一.事件回放  今天工作时碰到了一个奇怪的问题,这个问题很早很早以前也碰到过,不过没想到过这么久了竟然又栽在这里. 当时正在联调一个项目,由于后端没有提供数据接口,于是我直接本地建立了一个 json ...

  5. FZU 1018 枚举dp

    题意 给出一个数字组成的立方体 在其中选取一个体 使这个体中的数字之和最小 不可以不选 fzu的题目分类动态规划里面不是按难度排得 是按照题号..记得以前做题碰到过算 矩阵里面求子矩阵的最大和的 不会 ...

  6. 关于css3的自定义字体

    css3的@font-face属性打破了中文页面字体一成不变的格局,但今天本菜在用的时候并不那么爽.开始各种引用外部ttf文件失败.下了300M+的字体文件,苦逼的试了一下午.终于有一个ttf引用成功 ...

  7. 关于Try/Catch 代码块

    应当放在Try/Catch 代码块中的常见任务包括连接到一个数据库或与其交互.处理文件.调用Web 服务. 老实说,我这人很少有打破沙锅问到底的精神.不过昨晚听一技术人员跟他的项目经理说要在程序中使用 ...

  8. Ubuntu 12.04 Openstack Essex 安装(单节点)

    这是陈沙克一篇非常好的博文,当时在进行openstack排错的时候,多亏了这篇文章里面有些内容 帮我找到了问题的所在: 原文:http://www.chenshake.com/ubuntu-12-04 ...

  9. Bittersweet——NOIP2018 游记

    p { font-size: 16px; line-height: 1.5em; } blockquote { font-family: 'Times New Roman', 楷体; text-ali ...

随机推荐

  1. Windows历史

    1983年11月:Microsoft宣布Windows的第一个版本:以字符为基础 的窗口系统: 1985年11月:Windows1.0: 1990年5月:Windows 3.0(成功版本),16位OS ...

  2. Python学习笔记(九)

    Python学习笔记(九): 装饰器(函数) 内置函数 1. 装饰器 1. 作用域 2. 高阶函数 3. 闭包 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就 ...

  3. Oracle学习笔记之存储过程

                                                                                                        ...

  4. JAVA判断文件的内容类型

    Java 7 新的特性,判断文件的内容类型. Program to demonstrate Java 7 new feature : Determining the file content type ...

  5. 【ASP.NET MVC 学习笔记】- 15 Unobtrusive Ajax

    本文参考:http://www.cnblogs.com/willick/p/3418517.html 1.Unobtrusive Ajax允许我们通过 MVC 的 Help mothod 来定义 Aj ...

  6. Python 由__dict__和dir()引发的一些思考

    关于__dict__和dir()的区别和作用请参考这篇文章:http://blog.csdn.net/lis_12/article/details/53521554 说下我当时遇到的问题: class ...

  7. CentOS7安装GitLab、汉化及使用

    同步首发:http://www.yuanrengu.com/index.php/20171112.html 一.GitLab简介 GitLab是利用Ruby On Rails开发的一个开源版本管理系统 ...

  8. C++获取本机IP等信息

    运行环境:VS2008,win7,代码来源于MSDN,相关函数可以查看MSDN中的函数定义.. 代码如下: #include <winsock2.h> #include <ws2tc ...

  9. c++学习笔记---03---从一个小程序说起2

    从一个小程序说起2 要求:编写一个程序,要求用户输入一串整数和任意数目的空格,这些整数必须位于同一行中,但允许出现在该行中的任何位置.当用户按下键盘上的"Enter"键时,数据输入 ...

  10. mysql5.7.16安装 初始密码获取及密码重置

    在window7下面安装mysql5.7.16,出现一个问题,在初始化时,默认生成了一个密码,导致连接不了数据库.而在5.7以前,默认密码是空的,可以不用密码即可进入数据库.5.7之后的就遇到坑了,下 ...