最近重看activemq,对消息的传送确认机制有了进一步认识

1. mq在确认consumer收到消息后才会删除消息,因此consumer接收消息后应该进行ack"确认",javax.jms.Session接口中有四种ack模式:

  • AUTO_ACKNOWLEDGE = 1    自动确认
  • CLIENT_ACKNOWLEDGE = 2    客户端手动确认
  • DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
  • SESSION_TRANSACTED = 0    事务提交并确认

使用代码如下:

session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);  //(事务,ack模式)

若事务为true,用户指定的ACK模式将被忽略,而强制使用"SESSION_TRANSACTED"类型;

若事务为false,ACK模式不能设定为"SESSION_TRANSACTED"

ack指令又有几种类型,在JMS API中并没有定义ACT_TYPE,因为它通常是一种内部机制,并不会面向开发者,ActiveMQ中定义了如下几种ACK_TYPE:

  • DELIVERED_ACK_TYPE = 0    消息"已接收",但尚未处理结束
  • STANDARD_ACK_TYPE = 2    "标准"类型,通常表示为消息"处理成功",broker端可以删除消息了
  • POSION_ACK_TYPE = 1    消息"错误",通常表示"抛弃"此消息,比如消息重发多次后,都无法正确处理时,消息将会被删除或者DLQ(死信队列)
  • REDELIVERED_ACK_TYPE = 3    消息需"重发",比如consumer处理消息时抛出了异常,broker稍后会重新发送此消息
  • INDIVIDUAL_ACK_TYPE = 4    表示只确认"单条消息",无论在任何ACK_MODE下
  • UNMATCHED_ACK_TYPE = 5    在Topic中,如果一条消息在转发给“订阅者”时,发现此消息不符合Selector过滤条件,那么此消息将 不会转发给订阅者,消息将会被存储引擎删除(相当于在Broker上确认了消息)。

我们知道consumer有两种接收消息的方式:同步(onsumer.receive())和异步(consumer.setMessageListener),同步调用时,在消息从receive方法返回之前,就已经调用了ACK,根据不同ack模式处理(发送不同ack指令);异步调用时,消息的确认是在onMessage方法返回之后,如果onMessage方法异常,会导致消息不能被接收,会触发重发。

2. 对四种模式详细说明

2.1AUTO_ACKNOWLEDGE,

  • 在“同步”(receive)方法返回message之前,会检测optimizeACK选项是否开启,

   如果没有开启,此单条消息将立即确认,所以在这种情况下,message返回之后,如果开发者在处理message过程中出现异常,会导致此消息也不会redelivery,   即"潜在的消息丢失";如果开启了optimizeACK,则会在unAck数量达到prefetchSize * 0.65时确认,当然我们可以指定prefetchSize = 1来实现逐条消息确    认。

  • 在"异步"(messageListener)方式中,将会首先调用listener.onMessage(message),此后再ACK。

   如果onMessage方法异常,将导致client端补充发送一个ACK_TYPE为REDELIVERED_ACK_TYPE确认指令;

   如果onMessage方法正常,消息将会正常确认(STANDARD_ACK_TYPE)。

   此外需要注意,消息的重发次数是有限制的,每条消息中都会包含“redeliveryCounter”计数器,用来表示此消息已经被重发的次数,如果重发次数达到阀值,将   会导致发送一个ACK_TYPE为POSION_ACK_TYPE确认指令,这就导致broker端认为此消息无法消费,此消息将会被删除或者迁移到"dead letter"通道中。

   因此建议在onMessage方法中使用try-catch,这样可以在处理消息出错时记录一些信息,而不是让consumer不断去重发消息;如果你没有使用try-catch,就有可   能会因为异常而导致消息重复接收的问题,需要注意你的onMessage方法中逻辑是否能够兼容对重复消息的判断。

2.2CLIENT_ACKNOWLEDGE,在此模式下,开发者需要需要关注几个方法:

1) message.acknowledge(),

2) ActiveMQMessageConsumer.acknowledege(),

3) ActiveMQSession.acknowledge();

其1)和3)是等效的,将当前session中所有consumer中尚未ACK的消息都一起确认,2)只会对当前consumer中那些尚未确认的消息进行确认。开发者可以在合适的时机必须调用一次上述方法。

为了避免混乱,对于这种ACK模式下,建议一个session下只有一个consumer。

无论是“同步”/“异步”,ActiveMQ都不会发送STANDARD_ACK_TYPE,直到message.acknowledge()调用。如果在client端未确认的消息个数达到prefetchSize * 0.5时,会补充发送一个ACK_TYPE为DELIVERED_ACK_TYPE的"确认"指令,这会触发broker端可以继续push消息到client端。

2.3 DUPS_OK_ACKNOWLEDGE,它是一种潜在的"AUTO_ACK"确认机制,为批量确认而生,而且具有“延迟”确认的特点。对于开发者而言,这种模式下的代码结构和AUTO_ACKNOWLEDGE一样,不需要像CLIENT_ACKNOWLEDGE那样调用acknowledge()方法来确认消息。

1) 在ActiveMQ中,如果在Destination是Queue通道,我们真的可以认为DUPS_OK_ACK就是“AUTO_ACK + optimizeACK + (prefetchSize > 0)”这种情况,在确认时机上几乎完全一致;此外在此模式下,如果prefetchSize =1 或者没有开启optimizeACK,也会导致消息逐条确认,从而失去批量确认的特性。

2) 如果Destination为Topic,DUPS_OK_ACKNOWLEDGE才会产生JMS规范中诠释的意义,即无论optimizeACK是否开启,都会在消费的消息个数>=prefetchSize * 0.5时,批量确认(STANDARD_ACK_TYPE),在此过程中,不会发送DELIVERED_ACK_TYPE的确认指令,这是1)和AUTO_ACK的最大的区别。

这也意味着,当consumer故障重启后,那些尚未ACK的消息会重新发送过来。

2.4 SESSION_TRANSACTED,当session使用事务时,就是使用此模式。在事务开启之后,和session.commit()之前,所有消费的消息,要么全部正常确认,要么全部redelivery。

参考文章:

1. ActiveMQ消息传送机制以及ACK机制详解

2. ActiveMQ的消息重发策略和DLQ处理

3. ActiveMQ中Consumer特征详解与优化

4. ActiveMQ中Producer特性详解

JMS笔记(三)的更多相关文章

  1. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  2. 《CMake实践》笔记三:构建静态库(.a) 与 动态库(.so) 及 如何使用外部共享库和头文件

    <CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...

  3. Mastering Web Application Development with AngularJS 读书笔记(三)

    第一章笔记 (三) 一.Factories factory 方法是创建对象的另一种方式,与service相比更灵活,因为可以注册可任何任意对象创造功能.例如: myMod.factory('notif ...

  4. Python 学习笔记三

    笔记三:函数 笔记二已取消置顶链接地址:http://www.cnblogs.com/dzzy/p/5289186.html 函数的作用: 給代码段命名,就像变量給数字命名一样 可以接收参数,像arg ...

  5. 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现

    本系列文章由七十一雾央编写,转载请注明出处. 313239 作者:七十一雾央 新浪微博:http://weibo.com/1689160943/profile?rightmod=1&wvr=5 ...

  6. JMS笔记(二)

    接上篇 JMS笔记(一),启动ActiveMQ后,打开http://127.0.0.1:8161/admin管理界面,用户名admin密码admin,点击上面的Queues菜单,创建一个q_test_ ...

  7. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  8. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  9. 构建高性能WEB站点笔记三

    构建高性能WEB站点笔记三 第10章 分布式缓存 10.1数据库的前端缓存区 文件系统内核缓冲区,位于物理内存的内核地址空间,除了使用O_DIRECT标记打开的文件以外,所有对磁盘文件的读写操作都要经 ...

随机推荐

  1. Scapy

    1.UDP scanning with Scapy Scapy is a tool that can be used  to craft and inject custom packets into  ...

  2. sql语句的删除

    SQL中delete * from 和 delete from 有什么区别? 在SQL Server中两者没有区别,但在Oracle和MySQL的SQL语句中,delete * from是不标准的语法 ...

  3. matplotlib注解-【老鱼学matplotlib】

    本节讲述在图片中添加注解. 直接上代码: import numpy as np import pandas as pd import matplotlib.pyplot as plt # 生成x轴上的 ...

  4. SQL反模式学习笔记16 使用随机数排序

    目标:随机排序,使用高效的SQL语句查询获取随机数据样本. 反模式:使用RAND()随机函数 SELECT * FROM Employees AS e ORDER BY RAND() Limit 1 ...

  5. Python_queue单项队列

    队列(queue),实现程序间的松耦合 队列的三种类: class queue.Queue(maxsize)# 先进先出, maxsize 指定队列长度,线程安全的清况下,可以放入实例,对实例进行传输 ...

  6. ELK对Tomcat日志双管齐下-告警触发/Kibana日志展示

    今天我们来聊一聊Tomcat,相信大家并不陌生,tomcat是一个免费开源的web应用服务器,属于轻量级的应用程序,在小型生产环境和并发不是很高的场景下被普遍使用,同时也是开发测试JSP程序的首选.也 ...

  7. 合并K个排序链表

    合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [   1->4->5,   1->3->4,   2->6 ] 输出: 1-&g ...

  8. 删除倒数第k个元素

    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 ...

  9. Spring中RequestContextHolder以及HandlerInterceptorAdapter的使用

    1 . RequestContextHolder 的使用 想要使用RequestContextHolder,要在web.xml中配置RequestContextListener的监听才能使用. //全 ...

  10. H5唤醒app,不完全兼容

    ---ps---最近新发现一个开源的H5唤醒app的库:建议使用第三方开源库https://github.com/suanmei/callapp-lib实现:或者极光魔链(后期可能会收费)https: ...