前言
日常开发中,我们经常会碰到有延时任务的场景,譬如30分钟后关闭订单、在指定时间上架某个活动等,如果是最简单的场景,不考虑服务水平扩容、服务宕机等因素,可能内部用github.com/robfig/cron
加MYSQL存储延时信息即可。当然,一般线上服务,不可能不考虑道这些因素的影响,所以才有很多任务调度框架,比如:Quartz、xxl-job、Temporal等。但这次这里想讨论的是中间情况,也就是,既想保证服务能水平扩容、服务宕机任务不丢失,又不想使用那些调度框架(毕竟有部署成本和学习成本)。
延时任务存储
我们知道,要想服务能够自由地水平扩缩容,服务内部不能持有数据,也就是变成无状态服务,一般我们都选择放到Redis这种缓存框架中去。那对于延时任务来说,延时时间也是一种数据,我们把它存在哪里呢?首先不管存在哪里,一定要满足以下要求:
1. 截止时间到期后,能主动通知服务
这里肯定是要用PUSH的,如果存储器没有通知能力,那么只能用轮询的方案,但一是轮询的时间间隔不好设置,二是比较吃资源,三是任务的可靠性没有保障,如果轮询服务宕机,可能任务就得不到执行。
2. 保证任务执行的唯一性
一般来说,除非特殊需要,我们只想让延时任务只执行一次,比如指定时间上架活动,假如我们水平扩展了三个节点,总不能时间到期后三个节点同时做上架活动操作,这里就需要分布式协调机制。
3. 保证任务的可追溯性
比如任务即使到期了,通知也发出去了,但整个流程并没有结束,因为不能保证任务一定被执行了,如果通知消息没有被正确接收,被通知端需要有机制可以回溯消息。
那么,基于以上需求,我们依次来看手边常用的存储系统能否满足:
- 数据库
数据库一般没有主动通知的机制,要存到数据库,只能做轮询方案,这里直接PASS。 - Redis
Redis绝对是我们除了数据库外接触的