RabbitMQ 延时消息设计
问题背景
- 所谓"延时消息"是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费。
- 场景一:客户A在十二点下了一个订单,我想半个小时后来检查一下这个订单的付款状态,根据付款状态来作下一步的处理。 a. 针对场景一,建议采用方案数据库保存+schedule的方式也许更合适。
- 场景二:mdc系统更新了一个A信息,我要通知给A门店信息发生了变化,通知他们回调API来读取最新的值。
如果拿到消息后立即回调,可能因为mdc事务、缓存、从库延迟等原因,拿到变化前的信息,所以mdc希望能延迟一段时间再来消费此消息。
目标
- 可以实现消息按照自定义的时间延迟发送。
- 最好做到对消息生产者和消费者透明,不修改现有应用程序。
总体方案
3.1. 实现原理
- AMQP和RabbitMQ本身没有直接支持延迟队列功能,但是可以通过以下特性模拟出延迟队列的功能。
- RabbitMQ可以针对Queue和Message设置 x-message-ttl,来控制消息的生存时间,如果超时,则消息变为dead letter
- RabbitMQ的Queue可以配置x-dead-letter-exchange 和 x-dead-letter-routing-key(可选)两个参数,用来控制队列内出现了dead letter,则按照这两个参数重新路由。
结合以上两个特性,就可以模拟出延迟消息的功能
参考资料:
- https://www.cloudamqp.com/docs/delayed-messages.html
- http://www.rabbitmq.com/ttl.html
- http://www.rabbitmq.com/dlx.html
- http://www.rabbitmq.com/maxlength.html
3.2. 技术方案
|
方案一:针对Queue设置延迟时间 |
方案二:针对Message设置延迟时间 |
||
|
方案关键点 |
针对需要延迟的Queue配置ttl参数 |
针对Queue设置最大延迟时间 |
|
|
1. 优点: |
发送方对每个Message设置有效延迟时间 |
||
|
a. 维护简单 |
|||
|
b. 客户端完全透明 |
1. 优点 |
||
|
c. 针对每个延迟时间建立一个延迟队 |
a. 发送时可以自定义延迟时间 |
||
|
列 |
2. 缺点 |
||
|
2. 缺点: |
a. 需要升级客户端,对客户端不透明 |
||
|
a. 发送方无法自定义延迟时间 |
b. 需要针对每个队列建立不同的延迟 |
||
|
b. 延迟时间在建Queue时确定,修改 |
队列 |
||
|
不便 |
c. 带延迟参数的send方法容易误用, |
||
|
c. 修改延迟时间需要在MQ集群重新进 |
很难发现 |
||
|
行配置 |
|||
|
选择结果 |
最终选择了方案一 |
3.3. 消息发送流程
3.3.1. 原有业务流程

3.3.2. 自产自消的延迟消息流程

3.3.3. 普通的延迟消息流程

4. 操作步骤
4.1. 建立 delay.exchange

注意事项:
1. 不要设置为Internal,否则将无法接受dead letter
4.2. 建立延时队列(delay queue)

注意事项:
- 按照延期时间配置queue的名字,建议命名规则为delay.{time}.queue,使用delay前缀方便排序和做一些权限控制
- cos线上集群默认配置了delay.1m.queue、delay.5m.queue、delay.15m.queue三个队列
- 通过TTL设置队列的延期时间,对应不同的Queue
- MAX length为最大的积压的消息个数,推荐设置为100w~500w之间,推测方法见积压测试结果,
- 超过MAX length限制以后,队列头部的消息会立即转到delay.exchange进行投递,不会造成消息丢失
- 设置dead letter exchange为刚才配置的 delay.exchange
注意不要配置"dead letter routing key"否则会覆盖掉消息发送时携带的routingkey,导致后面无法路由
4.3. 配置延时路由规则
4.3.1. 需要延时的消息到exchange后先路由到指定的延时队列

4.3.2. delay.exchange 再重新把消息路由到正常的queue或exchang中

4.3.3. 消费者和以前一样从正常queue中接收消费消息
5. 积压消息测试结果
5.1. 积压测试结论
从实现原理上看,对于持久化消息,内存主要保存的是消息的索引数据,从测试结果也可以验证,可以得出以下数据:
- 内存占用方面估算
- 消息占用内存的大小确实和消息体本身大小无关,和消息个数直接相关。
- 消息体为40字节的字符串,积压10万消息,占用101MB内存,23万消息,占用230MB内存
- 消息体为一个整数,积压7万消息,占用64MB内存,24万消息,占用240MB内存
- 一个消息约占1KB的内存,以10GB内存,留一半余量:5GB/1K=500 0000
- 线上单个queue推荐线上的max length不要超过500万,根据延迟时间和消息量来调整此值的大小。
- 消息占用内存的大小确实和消息体本身大小无关,和消息个数直接相关。
- 消息量估算
- 以30分钟延迟,每秒发送1000个消息为例,则最大值为:30*60*1000=180 0000
- 倒推:以500万,30分钟延迟为例,则每秒最多发送的消息个数为:5000000/30/60=2777
- 消息积压数超过max length以后,消息不会丢失,只会导致消息会被提前消费。
结论:1. MAX length推荐这个值设置为100万~500万,既可以满足业务需求,又不超过内存限制
5.2. 40字节消息积压26万

5.3. 4字节消息积压7万

5.4. 4字节消息积压24万

5.5. 4字节消息积压31万

5.6. 4字节消息积压64万

总结:经过压测及基础配置,延时消息可以满足目前的需求,实现消息的延迟处理。
不知道延迟队列加上惰性队列的组合,即可以减小内存占用,又可以实现消息的延迟处理,也是一个非常好的方案。蛋糕和咖啡真的很配。
RabbitMQ 延时消息设计的更多相关文章
- RabbitMQ 延时消息队列
消息延时在日常随处可见: 1.订单创建10min之后不发起支付,自动取消. 2.30min定时推送一次邮件信息. 最常用到方式后台定时任务轮训,量小的时候可以使用,量大会出现数据读取会性能问题.Rab ...
- rabbitMq延时消息分级别
做支付平台的时候.需要实现接受上游支付消息,通知给下游渠道. 针对下游渠道:要实现 按通知次数 递进 延时通知 下游渠道的支付/签约/代扣的状态 可参考微信按照 15/15/30/180/1800/1 ...
- springboot项目整合rabbitMq涉及消息的发送确认,消息的消费确认机制,延时队列的实现
1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactI ...
- spring boot Rabbitmq集成,延时消息队列实现
本篇主要记录Spring boot 集成Rabbitmq,分为两部分, 第一部分为创建普通消息队列, 第二部分为延时消息队列实现: spring boot提供对mq消息队列支持amqp相关包,引入即可 ...
- RabbitMq(7)消息延时推送
应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给支付系统,通知支付系统将款打给商家,这个过程持 ...
- RabbitMQ实现延时消息的两种方法
目录 RabbitMQ实现延时消息的两种方法 1.死信队列 1.1消息什么时候变为死信(dead-letter) 1.2死信队列的原理 1.3 代码实现 1.4死信队列的一个小坑 2 .延时插件 2. ...
- SpringBoot | 第三十八章:基于RabbitMQ实现消息延迟队列方案
前言 前段时间在编写通用的消息通知服务时,由于需要实现类似通知失败时,需要延后几分钟再次进行发送,进行多次尝试后,进入定时发送机制.此机制,在原先对接银联支付时,银联的异步通知也是类似的,在第一次通知 ...
- Spring boot实战项目整合阿里云RocketMQ (非开源版)消息队列实现发送普通消息,延时消息 --附代码
一.为什么选择RocketMQ消息队列? 首先RocketMQ是阿里巴巴自研出来的,也已开源.其性能和稳定性从双11就能看出来,借用阿里的一句官方介绍:历年双 11 购物狂欢节零点千万级 TPS.万亿 ...
- C#调用RabbitMQ实现消息队列
前言 我在刚接触使用中间件的时候,发现,中间件的使用并不是最难的,反而是中间件的下载,安装,配置才是最难的. 所以,这篇文章我们从头开始学习RabbitMq,真正的从头开始. 关于消息队列 其实消息队 ...
随机推荐
- 利用搜狐新闻语料库训练100维的word2vec——使用python中的gensim模块
关于word2vec的原理知识参考文章https://www.cnblogs.com/Micang/p/10235783.html 语料数据来自搜狐新闻2012年6月—7月期间国内,国际,体育,社会, ...
- 关于《SQLSERVER走起》微信账号自动回复功能的升级
关于SQLSERVER走起微信账号自动回复功能的升级 由于腾讯对微信公众账号的升级,本公众账号也增加了关键词自动回复功能, 只需要输入某些特定关键词,本公众账号就会进行自动回复. 例如: 输入 sql ...
- Fedora 29 查看 rpm 包 依赖性 以 libconfig 为例
查看依赖性方法:# rpmrepater会向用户显示已安装包的列表,你可以使用上/下箭头来滚动屏幕# 可以在指定包上使用"r"键来显示其依赖关系,循环在指定包上按下"r& ...
- Windows 系统光盘刻录教程-光盘怎样刻录?刻录数据光盘用"轨道一次写入"还是"光盘一次写入"?
刻录光盘需要 DVD-RW 的光驱,并且光盘需要 DVD-R 的光盘用于刻录.刻录工具可以使用https://cn.ultraiso.net/ 来进行刻录.选择软件目录 中 工具 ,选择 刻录光盘映像 ...
- 第五章 绘图基础(BEZIER)
/*----------------------------- BEZIER.C -- Bezier Splines Demo (c) Charles Petzold, 1998 ---------- ...
- 关于解决JetBrains 激活问题
今天升级了下JetBrains 的一系列产品,安装后打开发现以前的激活失效了. 在网上看到网友们各类屏蔽和寻找服务器,尝试了下都不太方便. 最后去rover的个人博客看了下,很给力,总能跟上JetBr ...
- "error lnk1158 无法运行rc.exe”解决方案
最近使用VS2012编译时,出现" error lnk1158 无法运行rc.exe”的问题,无法编译生成.exe文件,连最基本的HelloWorld控制台程序都无法运行,重置了VS的默认设 ...
- Linux 小知识翻译 - 「packet」(网络数据包)
用手机接收邮件或者访问网页的时候,一般会说有「packet费用」(这是日本的说法,在中国好像一般都说 “流量费”),即使对网络不太熟悉的人也知道「packet」这个词(这里也是日本的情况). 那么,「 ...
- Alpha冲刺!Day13 - 小结
Alpha冲刺!Day13 - 小结 各个成员今日完成的任务 今天团队极限编程12小时,从早上九点要求每个人给出一张电脑全屏截图以示开始干活,每两小时汇报进度确认已经做了什么.现在在做什么. 各节点列 ...
- EBS-新增和更新价目表行
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/gh320/article/details/36666133 新增和更新价目表行 --目的:在已 ...