每日一博 - 使用环形队列实现高效的延时消息

举报
小工匠 发表于 2021/09/09 23:51:16 2021/09/09
【摘要】 文章目录 Pre方案A方案B总结 Pre 来个场景: 24小时后将未进行某个Action的业务,执行另外一个动作。 比如 24小时未付款的订单,取消。 你可能会说 方案...

文章目录

在这里插入图片描述


Pre

来个场景: 24小时后将未进行某个Action的业务,执行另外一个动作。 比如 24小时未付款的订单,取消。

你可能会说

在这里插入图片描述


方案A

来个定时呗 ,每隔半小时 ,扫描数据库订单表,将完成时间超过24小时的订单,取消掉。

在这里插入图片描述

But…

这方案有些明显的缺点啊,老哥

  • (1)轮询效率比较低

  • (2)时效性不好,假设每小时轮询一次,最坏的情况下,时间误差会达到1小时;


那如何既保证效率的同时,又保证实时性呢?

在这里插入图片描述


方案B

来说下核心思路

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

  • 环形队列。例如可以创建一个大小为3600的环形队列

  • 任务集合。环上每一个格是一个Set

同时,启动一个timer:

  • 每隔1s,timer在环形队列中移动一格

  • 用一个Current Index来标识当前所在的格;

Task结构中包含两个重要属性:

  • Cycle-Num:用于标记当第几圈扫描到这个格时,执行任务

  • Task-Function:到时间后需要执行的任务函数

在这里插入图片描述

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

  • (1)计算这个Task应该放在哪一个格,现在是在第1格,3610秒之后,应该是第11格,所以这个Task应该加入第11格的Set<Task>中;

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

Current Index每秒移动一格,当移动到下一格时,遍历这个格的Set,看看每个Task的Cycle-Num是不是0:

  • 如果不是0,说明任务时间还没到,还需要多移动几圈,将Cycle-Num减1;

  • 如果是0,说明到这个Task的执行时间了,取出Task-Funciton丢给工作线程执行,并把这个Task从Set<Task>中删除

 Warning : 不要直接用timer线程来执行任务

  
 
  • 1

总结

总体思路就是这个样子,总结下有点

  • (1)效率高,无需再轮询订单表;一个订单,任务只执行一次

  • (2)实时性好,精确到秒
    在这里插入图片描述

文章来源: artisan.blog.csdn.net,作者:小小工匠,版权归原作者所有,如需转载,请联系作者。

原文链接:artisan.blog.csdn.net/article/details/119258887

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。