1分钟实现“延迟消息”功能 ----自己理解为订单失效之类的功能

转载 2018年04月17日 13:17:26

1分钟实现“延迟消息”功能

原创 2017-03-15 58沈剑 架构师之路

一、缘起

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

 

例如:滴滴打车订单完成后,如果用户一直不评价,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环形队列,例如可以创建一个包含3600slot环形队列(本质是个数组)

2任务集合,环上每一个slot是一个Set<Task>

 

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

 

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

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

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

 

 

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

1计算这个Task应该放在哪一个slot,现在指向13610秒之后,应该是第11格,所以这个Task应该放在第11slotSet<Task>

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

 

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

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

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

 

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

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

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

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

 

三、总结

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


另外,关于MQ的可达性、幂等性未来撰文另述。

 

如果对文章和配图满意的话,帮忙转发一下哈。

Spring核心功能指南

-
  • 1970年01月01日 08:00

1分钟实现“延迟消息”功能(58沈剑)

一、缘起 很多时候,业务有“在一段时间之后,完成一个工作任务”的需求。   例如:滴滴打车订单完成后,如果用户一直不评价,48小时后会将自动评价为5星。 一般来说怎...
  • jiangzhexi
  • jiangzhexi
  • 2017-03-16 22:09:26
  • 459

1分钟实现“延迟消息”功能

一、缘起 很多时候,业务有“在一段时间之后,完成一个工作任务”的需求。   例如:滴滴打车订单完成后,如果用户一直不评价,48小时后会将自动评价为5星。 一般来说怎么实现这...
  • u011676417
  • u011676417
  • 2017-03-19 12:13:40
  • 290

高效实现延迟消息功能

高效实现延迟消息功能 高效延时消息,包含两个重要的数据结构: (1)环形队列,例如可以创建一个包含3600个slot的环形队列(本质是个数组) (2)任务集合,环...
  • chenglinhust
  • chenglinhust
  • 2017-06-04 08:53:29
  • 569

JavaEE结合quartz实现订单自动失效功能

总有话要说在前头 不管是做电子商务平台还是其他的什么系统,只要涉及到订单就肯定有订单超时自动失效的功能。本篇文章将使用quartz初步解决这个问题。 在数据量较小的情况,我们可以采用quartz定时...
  • csu_passer
  • csu_passer
  • 2017-10-26 12:34:27
  • 187

RabbitMQ 延迟队列实现订单支付结果异步阶梯性通知

在第三方支付中,例如支付宝、或者微信,对于订单请求,第三方支付系统采用的是消息同步返回、异步通知+主动补偿查询的补偿机制。 由于互联网通信的不可靠性,例如双方网络、服务器、应用等因素的影响,不管是...
  • nongfuyumin
  • nongfuyumin
  • 2017-12-18 16:56:59
  • 785

实现“延迟消息”功能

转自:http://mp.weixin.qq.com/s/eDMV25YqCPYjxQG-dvqSqQ 一、缘起 很多时候,业务有“在一段时间之后,完成一个工作任务”的需求。 ...
  • lr131425
  • lr131425
  • 2017-05-02 14:49:04
  • 88

订单超时自动关闭的实现方案总结

统一来说,业务有“在一段时间之后,完成一个工作任务”的需求。 实现这种定时任务有哪些方法呢,来总结一下想到的方法。 一、定时轮询 这是一个比较直接的思路,启动一个计划任务,每隔一定时间处理一次,...
  • verifocus
  • verifocus
  • 2018-01-23 09:33:10
  • 1128

JS定时提醒功能

  • 2013年11月29日 15:43
  • 2KB
  • 下载
收藏助手
不良信息举报
您举报文章:1分钟实现“延迟消息”功能 ----自己理解为订单失效之类的功能
举报原因:
原因补充:

(最多只允许输入30个字)