首页 > 其他分享 >解决某些有到期时间的场景,不适合定时扫描表来完成处理的情况

解决某些有到期时间的场景,不适合定时扫描表来完成处理的情况

时间:2023-02-20 16:33:56浏览次数:58  
标签:slot slotIndex uid map 队列 扫描 定时 listLoop 表来


有几个场景业务的处理:

一:有一个很大的商品订单表,每天新增数十万条数据。每条数据有个到期时间,需要在到期时间后做一些处理,譬如关闭订单,改变状态之类的。

二:有个付款功能,有到期时间,时间到了需要关闭,或者通知用户等等。

三:抢购时,时间到了,用户不处理不付款的,要把商品回到库存里之类的。

大概类似的一些有到期时间功能的业务场景,但是要么是有较强的实时性,譬如希望到期后立马就改变状态或者做出一些通知之类的,要么是数据量巨大的。

那么可能首先想到的思路就是开个定时任务,隔一段时间去扫一下表,看看到期时间,然后做处理。

很明显,扫表是个很大的工作量,耗时耗资源,甚至会产生死锁什么的。而且大部分时候的扫描是无用的,产生了很多无用的查询。

 

那么这种问题是解决思路:

在添加数据时,将ID和过期时间放到redis里,用那个能排序的结构sortSet,或者类似的能记录时间的中间件,做好排序。然后起个后台任务或者新起个项目,专门是扫描这个redis的第一条数据,也就是最快要过期的,这样只需要查询一条就行了,只要第一条不过期,那后面的就不用看了,也就不需要去操作数据库。倘若第一条过期了,就做相应的处理,然后移除掉,再去扫第二条,依次类推。这样查询就很少,也不需要查表。所以可以把扫描间隔设的很短,来达到强实时性。

 

**************************************************

补充1:

阿里云消息队列ONS服务,里面有一个发送延时消息(定时消息)的功能,这个也可以应用于该场景,逻辑执行完毕后,譬如下单成功,30分钟后不付款就取消订单,那么就可以使用阿里的发送延时消息的功能。30分钟后消息发出,然后处理端去获取付款状态,如果未付款则取消订单。

**************************************************

补充2,今天看了一篇定时任务高效触发的文章,摘录部分

开发中我们经常会遇到一些需要定时来解决的业务场景。比如,有这样一个需求:“如果连续30s没有请求包(例如登录,消息,keepalive包),服务端就要将这个用户的状态置为离线”。

 

环形队列处理

 

​​数据结构​​:

  • 环形队列ListLoop,例如可以创建一个包含0-30的slot**环形队列**(本质是个数组);
  • 每个环上的任务集合Slot,环上每一个slot是一个Set;
  • 记录每个Task对应落到Slot的Map集合;

执行过程: 
第一步:启动一个timer,每隔1s,在上述环形队列中移动一格,​​​0->1->2->3…->29->30->0…​​​有一个CurrentSlotIndex指针来标识刚检测过的slot ; 
第二步:当有某用户uid有请求包到达时,从Map结构中,查找出这个uid存储在哪一个slot里; 
第三步:如果存在,从这个slot的Set结构中,删除这个uid,否则跳过该步骤; 
第四步:将uid重新加入到新的slot中(CurrentSlotIndex指针所指向的上一个slot)因为这个slot,会被timer在30s之后扫描到 
第五步:更新Map,重新设置该uid对应slot的index值

解决某些有到期时间的场景,不适合定时扫描表来完成处理的情况_环形队列

// new Array(31).fill(new Set())
// No,数组中所有Set集合为同一个

let listLoop = new Array(31),
map = new Map(), // 记录每个uid的slotIndex
currentSlotIndex = 1; // 当前要检测的slot

function doAction(uid) {
// 如果循环队列中已存在该uid,需要先干掉,重新计时
let slotIndex = map.get(uid);
slotIndex && listLoop[slotIndex].delete(uid);
// 将该uid重现添加到循环队列中
// 周期31,新插入的置入当前的后一个(即,30s后可以扫描到它)
// 更新map中这个uid的最新slotIndex
slotIndex = currentSlotIndex - 1;
listLoop[slotIndex] = listLoop[slotIndex] ?
listLoop[slotIndex].add(uid) : new Set().add(uid);
map.set(uid, slotIndex);
}

// 每秒钟移动一个slot,这个slot对应的set集合中所有uid都为超时
// 如果所有slot对应的set集合都为空,则表示没有uid超时
setInterval(function() {
var slotSet = listLoop[currentSlotIndex];
if(slotSet && slotSet.size > 0) {
for(let uid of slotSet.values()) {
// 执行完的uid从map集合中剔除
map.delete(uid);
console.log(`<${uid}>超过30s未做任何操作,设置为离线!`);
}
// 置空该集合
slotSet.clear();
}
// 指标继续+1
currentSlotIndex = (++currentSlotIndex) % 31;
}, 1000);

// 思路、注意Map集合的内心移除情况。


方案的优点:

  • 无需再轮询全部订单,效率高
  • 无重复执行,一个订单,任务只执行一次
  • 效性好,精确到秒(控制timer移动频率可以控制精度)

参照文章:​​10w定时任务,如何高效触发超时​​​、​​1分钟实现“延迟消息”功能​

举一反三

上述展示描述了一种业务场景,通过环形队列的方式我们还可以处理很多类似场景。

  • 某打车软件订单完成后,如果用户一直不评价,48小时后会将自动评价为5星;
  • 某数据产品用户修改设置,1小时后生效;

 

标签:slot,slotIndex,uid,map,队列,扫描,定时,listLoop,表来
From: https://blog.51cto.com/u_13706148/6068706

相关文章

  • 多级缓存机制(包括缓存的主动过期、定时过期、被动过期)源码剖析
    1多级缓存入口2初始化缓存3二级缓存(读写缓存)readWriteCacheMap,每隔180s就会主动过期4一级缓存(只读缓存)readOnlyCacheMap,每隔30s自动刷新一次(定时过期)5......
  • uni-app api:扫描二维码(hbuilderx 3.6.18)
    一,代码:<template><view><button@click="scanCode">扫码</button><text>扫码类型:{{scanType}}</text><text>扫码内容:{{result}}</text>......
  • APIKiller--一款甲方扫描【神】器
    APIKiller--一款漏洞扫描(神)器Github项目直通车:APIKillerAPISecurityTool原文参考:https://aur0ra.cn/3-apikiller/项目背景去年有幸进入字节无恒实验室实习,并负......
  • STM32 - 定时器1 - 定时器详解
    目录1.什么是定时器1.1数量&来源1.2用途2.通用定时器框图2.1输入时钟2.2时基单元2.3输入捕获/输出比较通道1)输入阶段:2)输出阶段:3.模式配置3.1计数器模式3.2输入捕......
  • python定时器
    一.TimerTimer为threading中的一个类,用来指定的秒数后调用函数,我们来看下Timer类的构造参数。interval:设置定时运行的时间function:设置定时的事件args:参数kwargs:字典......
  • 企业做漏洞扫描的意义有哪些?
    从网络兴起至今,利用漏洞的网络安全事件从未间断,而且近两年还呈现了日趋严重的态势。放眼全球,因为漏洞导致直接经济损失的不计其数,对于企业而言更是考验,漏洞的暴露和被利用不......
  • 通过Windows定时任务执行Python脚本给钉钉群发送消息
    前提:已经存在有成功发送钉钉群机器人消息的python脚本,参考上一篇Python调用钉钉群机器人发送群消息Windows定时任务设置1、本机是Win7系统:控制面板->系统和安全->管理工......
  • 定时任务corn表达式解析
    corn分为两种,长度为6和长度为7的情况秒分时日月周秒分时日月周年符号:秒分时:,*-/日:,*-/+?W(工作日)L(最后)C......
  • K8s:开源安全平台 kubescape 实现 Pod 的安全合规检查/镜像漏洞扫描
    写在前面生产环境中的k8s集群安全不可忽略,即使是内网环境容器化的应用部署虽然本质上没有变化,始终是机器上的一个进程但是提高了安全问题的处理的复杂性分享一个开......
  • .NET 纯原生实现 Cron 定时任务,未依赖第三方组件
    常用的定时任务组件有Quartz.Net和Hangfire两种,这两种是使用人数比较多的定时任务组件,个人以前也是使用的Hangfire,慢慢的发现自己想要的其实只是一个能够根据Cron......