定时任务&延时任务
可以理解定时任务是延时任务的周期执行形式
方案
- 轮询
- Java DelayQue(小根堆)
- netty时间轮算法
- redis有序集合
- redis key过期通知(发布订阅)
- 消息队列的延时消息
思考:单机&分布式
现在有一个延时任务,要想实现可靠执行,必须将任务持久化,比如数据库或者消息队列,数据库扫库或者消息队列的延时消息。如果是定时任务。因为执行完成后要重新设置任务下一次执行时间,如果是数据库,就经历扫库->查询每一条任务,当前任务现在可以执行,执行完成后修改任务下一次的执行时间。如果是单线程,可以不考虑幂等问题,但如果是多线程或者分布式,那可能会出现多个线程同时拿到同一个任务执行,执行完成后设置任务的下一次执行时间,需要确保任务的幂等和任务的执行成功,比如A线程拿到任务1后,执行,但机器宕机了,需要下一个线程接上,B线程继续执行,如果B线程也因为意外退出了或者还没来得及更新任务的下一次执行时间退出了,其他线程需要接上,实现方案是分布式锁或者zk选举,拿到锁的线程才能执行任务。数据库实现起来成本太大,有其他的方案大家可以交流一下
思考:延时算法
类似Java DelayQue的小根堆,netty的时间轮算法,最简单是轮询判断。
小根堆实现
现在有一个数据结构,维护一组任务,任务有创建时间和延时时间属性,这个数据结构支持动态添加任务,会按照下一次执行的时间进行排序,很容易想到用堆,堆支持动态添加元素,动态获取当前最小/最大的元素,每次拿出当前最小的元素,如果当前最小的元素可以执行,那就执行,不可以执行那就睡眠一段时间,如果有新的任务添加进来,那就提前唤醒睡眠的线程,重新按从小到大的顺序维护小根堆