rabbitMQ实现延迟消息队列

一、延迟消息适应场景

一般延迟队列用于特定事件发生后隔一段时间需要做特定处理的场景,下面举几个常见的栗子

1.电商系统中,若用户下单后30min不支付,自动取消订单
2.用户登录APP浏览特定商品20min后还没下单,自动推送商品评测信息的消息并发放商品相关优惠券

二、rabbitMQ的延迟消息

Rabbitmq本身是没有延迟队列的,要实现延迟消息,一般有两种方式:

1.通过Rabbitmq本身队列的特性来实现,需要使用Rabbitmq的死信交换机(Exchange)和消息的存活时间TTL(Time To Live)
2.在rabbitmq 3.5.7及以上的版本提供了一个插件(rabbitmq-delayed-message-exchange)来实现延迟队列功能。同时插件依赖Erlang/OPT 18.0及以上

一个个来看

三、rabbitMQ不使用插件实现延迟消息

3.1 原理图解

rabbitMQ延迟消息原理.png

若想不借助插件实现rabbitMQ的延迟消息,实际就是利用一个没有消费者的Queue1,等待消息过期后,通过交换机转发到Queue2来进行消费,消息的延迟时间就是消息在Queue1中的存活时间

3.2 在一个传统的spring项目中配置rabbitMQ的延迟消息

3.2.1 创建一个自动过期的消息队列(Queue1)

此队列没有消费类,可以通过x-message-ttl设置消息过期的时间,默认单位是毫秒,通过x-dead-letter-exchange设置死信后转发的交换机,通过x-dead-letter-routing-key来设置死信交换机中,真正需要转发的绑定的key,例如一个延迟5分钟的延迟队列的配置可以为:

 <rabbit:queue id="delayFiveMinuteQueue"  durable="true" auto-delete="false" exclusive="false" name="delayFiveMinuteQueue">
        <rabbit:queue-arguments>
            <!-- 设置延迟队列的过期时间 -->
            <entry key="x-message-ttl" value="300000" value-type="java.lang.Integer"/>
            <entry key="x-dead-letter-exchange" value="mq-exchange" />
            <entry key="x-dead-letter-routing-key" value="delayConsumerQueue" />
        </rabbit:queue-arguments>
</rabbit:queue>
3.2.2 创建转发后的消息队列(Queue2)

此队列为转发后的队列,故需要有消费类,其配置和一般的队列保持一致,例如

<!-- 延迟消息的消费队列 -->
<rabbit:queue id="delayConsumerQueue" durable="true" auto-delete="false" exclusive="false"  name="delayConsumerQueue"/>
3.2.3在交换机上进行绑定

交换机需要绑定队列和转发的key之间的关系,故需要注意的是Queue1的x-dead-letter-routing-key一定要和交换机中Queue2绑定的key保持一致,例如上述两个队列绑定后的配置示例为:

<rabbit:direct-exchange name="mq-exchange" durable="true" auto-delete="false" id="mq-exchange">
        <rabbit:bindings>
            <rabbit:binding queue="delayConsumerQueue" key="delayConsumerQueue" />
            <rabbit:binding queue="delayFiveMinuteQueue" key="delayFiveMinuteQueue" />
        </rabbit:bindings>
</rabbit:direct-exchange>

3.3不使用插件实现延迟消息的局限性

可以看到如果不使用插件,延迟消息的延迟时间是依赖于Queue1的x-message-ttl的,也就是说,需要支持多少种延迟的时间,就得提前设置好多少个无消费类的Queue,而且由于转发绑定的Queue2需要配到交换机中,比较死板,而真实的业务中消费类肯定是不一样的,故我真正在实现的时候在发到Queue1之前把消息体及需要消费的Queue(假设名称为Queue3)进行了落库,Queue2中进行消费时,实际是查库把消息读出来然后发送到了Queue3

而如果使用插件就没有以上的局限

四、rabbitMQ使用插件实现延迟消息

4.1 插件简介

在rabbitmq 3.5.7及以上的版本提供了一个插件(rabbitmq-delayed-message-exchange)来实现延迟队列功能。同时插件依赖Erlang/OPT 18.0及以上。

插件源码地址:
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange

插件下载地址:
https://bintray.com/rabbitmq/community-plugins/rabbitmq_delayed_message_exchange

4.2 插件使用方式

4.2.1 安装

进入插件安装目录

{rabbitmq-server}/plugins/(可以查看一下当前已存在的插件)

下载插件

wget https://bintray.com/rabbitmq/community-plugins/download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez

(如果下载的文件名称不规则就手动重命名一下如:rabbitmq_delayed_message_exchange-0.0.1.ez)

4.2.2 启用插件

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

(关闭插件)
rabbitmq-plugins disable rabbitmq_delayed_message_exchange

4.2.3 插件使用

在需要发送延迟消息队列的项目中,声明一个x-delayed-message类型的交换机来使用delayed-messaging特性,注意这个交换机并不是rabbitmq本身的,而是插件提供的,一定要是x-delayed-message类型,绑定的queue就是正常的queue即可,不需要额外多余的queue(这是和不用插件方式的最大区别及好处),例如

<rabbit:direct-exchange name="mq-exchange-delayed" durable="true" auto-delete="false" id="mq-exchange-delayed" delayed="true">
    <rabbit:bindings>
         <rabbit:binding queue="demoQueue" key="demoQueue"/>
    </rabbit:bindings>
</rabbit:direct-exchange>

消息发送时,在header添加"x-delay"参数来控制消息的延时时间,如果使用的是spring-rabbit中的RabbitTemplate,只需要通过messageProperties.setDelay(delay)方法set上延迟时间即可(单位为毫秒)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容