更优雅的延迟执行实现---环形队列

在做业务时经常遇到某些一次性的延迟需求,比如新闻的定时发布,过了一个时间阈值后某个任务的状态置为超时或触发某个接口。

之前实现这种一次性的延迟需求基本会有3种思路。

(1)线程轮询扫库

(2)Timer类

(3)定时框架Quartz

这三种方案都存在各自的问题

对于“线程轮询扫库”,性能开销巨大,实时性差

对于“Timer类”来说,假如项目重启,之前设置的定时就荡然无存

对于“定时框架Quartz”虽然支持DBstore,但是框架太过于重量级。

如何优雅而又高效的实现一个延迟任务呢?前不久看到一篇文章 https://mp.weixin.qq.com/s/eDMV25YqCPYjxQG-dvqSqQ ,似乎提供了一个不错的解法。

按照思路我自己实现了一个环形队列,https://git.oschina.net/spjich/RingQueue.git

引用文章里的一个图片:

 

 

这篇文章只是提出一个解决的思路,但是有几个问题并未说明

1.这种定时类似于内存里的状态机,是内存就必然会重启清除。 解决方案:需要将任务录入DB一份,重启项目构造环形队列时实现AbstractRingQueue的initData方法,将DB中还未完成的任务重新加载进来运行

2.大规模集群环境下如何保证正常运行? 解决方案:这点非常关键,在集群条件下,如果项目重启,那么一个任务就会被执行n次,此时我想到的解决方案是根据某种规则进行数据的初始化,比如某个集群里有3台机器编号分别为1,2,3,那么每台在initData的时候分别加载 taskId%3-机器编号=0 的任务。当然我提出的这种方案并不是最好的,他同样会存在热点问题,会使某台机器上运行的task比其他机器上多,大体解决思路可以参考一些负载均衡策略。

另外纠正下文章最后说“开源的MQ好像都不支持延迟消息”这句话,据我所知阿里的RocketMQ是支持延迟消息的。

原创文章转载请声明出处:http://spjich.iteye.com/blog

猜你喜欢

转载自spjich.iteye.com/blog/2364114