美文网首页MQ
MQ之如何做到消息延时

MQ之如何做到消息延时

作者: duzhongli | 来源:发表于2017-09-20 11:48 被阅读47次

一、缘起

很多时候,业务有“在一段时间之后,完成一个工作任务”的需求。

例如:滴滴打车订单完成后,如果用户一直不评价,48小时后会将自动评价为5星。

一般来说怎么实现这类“48小时后自动评价为5星”需求呢?

常见方案:启动一个cron定时任务,每小时跑一次,将完成时间超过48小时的订单取出,置为5星,并把评价状态置为已评价。

假设订单表的结构为:t_order(oid, finish_time, stars, status, …),更具体的,定时任务每隔一个小时会这么做一次:

select oid from t_order where finish_time > 48hours and status=0;

update t_order set stars=5 and status=1 where oid in[…];

如果数据量很大,需要分页查询,分页update,这将会是一个for循环。

方案的不足:

(1)轮询效率比较低

(2)每次扫库,已经被执行过记录,仍然会被扫描(只是不会出现在结果集中),有重复计算的嫌疑

(3)时效性不够好,如果每小时轮询一次,最差的情况下,时间误差会达到1小时

(4)如果通过增加cron轮询频率来减少(3)中的时间误差,(1)中轮询低效和(2)中重复计算的问题会进一步凸显

如何利用“延时消息”,对于每个任务只触发一次,保证效率的同时保证实时性,是今天要讨论的问题。

二、高效延时消息设计与实现

高效延时消息,包含两个重要的数据结构:

(1)环形队列,例如可以创建一个包含3600个slot的环形队列(本质是个数组)

(2)任务集合,环上每一个slot是一个Set

同时,启动一个timer,这个timer每隔1s,在上述环形队列中移动一格,有一个Current Index指针来标识正在检测的slot。

Task结构中有两个很重要的属性:

(1)Cycle-Num:当Current Index第几圈扫描到这个Slot时,执行任务

(2)Task-Function:需要执行的任务指针

假设当前Current Index指向第一格,当有延时消息到达之后,例如希望3610秒之后,触发一个延时消息任务,只需:

(1)计算这个Task应该放在哪一个slot,现在指向1,3610秒之后,应该是第11格,所以这个Task应该放在第11个slot的Set中

(2)计算这个Task的Cycle-Num,由于环形队列是3600格(每秒移动一格,正好1小时),这个任务是3610秒后执行,所以应该绕3610/3600=1圈之后再执行,于是Cycle-Num=1

Current Index不停的移动,每秒移动到一个新slot,这个slot中对应的Set,每个Task看Cycle-Num是不是0:

(1)如果不是0,说明还需要多移动几圈,将Cycle-Num减1

(2)如果是0,说明马上要执行这个Task了,取出Task-Funciton执行(可以用单独的线程来执行Task),并把这个Task从Set中删除

使用了“延时消息”方案之后,“订单48小时后关闭评价”的需求,只需将在订单关闭时,触发一个48小时之后的延时消息即可:

(1)无需再轮询全部订单,效率高

(2)一个订单,任务只执行一次

(3)时效性好,精确到秒(控制timer移动频率可以控制精度)

三、总结

环形队列是一个实现“延时消息”的好方法,开源的MQ好像都不支持延迟消息,不妨自己实现一个简易的“延时消息队列”,能解决很多业务问题,并减少很多低效扫库的cron任务。

相关文章

  • MQ之如何做到消息延时

    一、缘起 很多时候,业务有“在一段时间之后,完成一个工作任务”的需求。 例如:滴滴打车订单完成后,如果用户一直不评...

  • mq延时消息

    原本想写下kafka事务的很多大神都写了,在此引用一篇大佬的文章吧http://www.jasongj.com/k...

  • MQ之如何做到消息必达

    一、架构方向 MQ要想尽量消息必达,架构上有两个核心设计点: (1)消息落地 (2)消息超时、重传、确认 二、MQ...

  • MQ之如何做到消息幂等

    一、缘起 MQ消息必达,架构上有两个核心设计点: (1)消息落地 (2)消息超时、重传、确认 再次回顾消息总线核心...

  • 如何在MQ中实现支持任意延迟的消息?

    如何在MQ中实现支持任意延迟的消息? 什么是定时消息和延迟消息? 定时消息:Producer 将消息发送到 MQ ...

  • 第三章-高级特性1:Confirm

    消息如何保证100%的投递成功 保障消息的成功发出 保障MQ节点的成功接收 发送端收到MQ节点(Broker) 确...

  • RabbitMQ指南之一:"Hello World!"

    为什么要使用MQ消息中间件?它解决了什么问题?关于为什么要使用消息中间件?消息中间件是如何做到同步变异步、流量削锋...

  • RabbitMQ指南之一:"Hello World!&

    为什么要使用MQ消息中间件?它解决了什么问题?关于为什么要使用消息中间件?消息中间件是如何做到同步变异步、流量削锋...

  • 消息队列

    MQ的作用 消息通信MQ的基础功能即为消息通信。使用MQ的客户端可以将消息发送到MQ中,也可以从MQ中消费消息。 ...

  • ActiveMQ

    一. 引言 ActiveMQ扩展出:API 接受发送MQ 的高可用MQ 的集群容错配置MQ 的持久化延时发送签收机...

网友评论

    本文标题:MQ之如何做到消息延时

    本文链接:https://www.haomeiwen.com/subject/rvansxtx.html