例如:每天1000W订单,PM要求24小时自动5星好评,就可以用延时任务来进行处理。一般如何怎么实现这类需求?
最容易想到的:启动一个定时任务,每小时跑一次,将完成时间超过24小时的未评价订单取出,自动评为5星。
这个方法有什么缺点?
时效性不够好,如果每小时跑一次定时任务,最差的情况下,时间误差会达到1小时。
画外音:当然,对于24小时自动好评的场景,1个小时的误差业务可以接受。
缩短定时任务执行周期,例如每秒一次,能解决时效性的问题吗?
时效性能解决,但效率更低了:1秒钟搜索一次全量数据,却只捞出少量(几百个)符合要求的订单。
有什么高效解决延时任务的方法吗?
时间轮。
时间轮的基础结构如何?
1. 创建一个下标从0到86400的环形队列(本质是个数组);
2. 数组的每个slot元素,是一个订单id的集合,表示在这一秒钟,订单完成;
画外音:每个Set里,只有几百个oid。
3. 启动一个timer,每隔1s,在环形队列中移动一格,这一格里的Set,全部设置为5星好评;
订单完成时,oid怎么加入slot?
每当有新订单完成,就将订单id加入当前正在扫描的slot的前一个slot。
为什么是前一个slot?
因为前一个slot将在86400秒之后被扫描到。1s扫一格,下一次被扫描到的时候,就是24小时,需要被设置5星好评之时。
如果用户手动评价,怎么将oid从slot中删除呢?
加一个Map,记录订单id对应的slot下标。用户手动评价,就将对应的oid从slot里删除,避免被扫描到触发默认好评。
这个方案有什么优点?
1. 只有一个timer,不耗内存资源;
2. 时间精度高,可以精确到秒,如果想要更精确,增加slot的数量就行了;
3. 每个订单只会处理一次,效率高;
4. 每个slot里的集合批量好评,业务处理快。
另外,时间轮是一个通用的方法,Set中可以是任何task,本文的oid是一个最简单的举例。
《A hierarchical timer wheel》https://www.snellman.net/blog/archive/2016-07-27-ratas-hierarchical-timer-wheel/文章不长,可扩展阅读。
==全文完==
宝藏号,日更。
点赞,转发,在看,感激不尽!