方案1:统一的定时任务,每隔1分钟执行一次。
缺点:每隔一分钟处理一次,过于频繁的请求,增加服务器的负担。并且会有1分钟的误差,因为定时任务设置每隔1分钟执行一次。
优点:实现简单
方案2:利用mq的延迟发送特性处理+一个定时任务统一处理失败的单子
下单后,发送一条消息给mq,并设置mq,30分钟后再处理发送消息动作
优点:时间准确性相对高,一个单子只执行一次,并发高。
缺点:1.当大量消息堆积的时候,同样存在延迟的问题。同时还可能存在消息丢失风险。(rocketmq号称0丢失)
2.基本上的mq,都是默认不开启延迟发送的,需要开启mq延迟发送功能,且会增加mq的一部分性能负担。
方案3:利用redis的过期key特性处理+一个定时任务统一处理失败的单子
优点:时间准确性相对高,一个单子只执行一次
缺点:1,消息只发送一次,不管有没有处理成功。
2,当很多key同时过期时,存在延迟问题。
3. 当负载多个实例的时候,要保证业务只被执行一次,要保证幂等性,不能重复被执行。
4,redis默认是不开启这个功能的,需要开启redis过期key的监听订阅,会增加redis的一部分性能负担。
方案4:30分钟后处理的定时任务+一个定时任务统一处理失败的单子
当下单后,新建一个30分钟后处理的定时任务
优点:时间准确性高,一个单子只执行一次。
缺点:1,需要再新建一个定时任务,删除处理过,无用的定时任务。
2,并发数,依赖数据库的并发,以xxjob来举例,其实是往数据库插一条定时任务的数据,所以并发受限于数据库并发数。(需要优化插入的过程,比如如何提高插入速度,或者相应的削峰措施等)
上面四种方案,笔者认为在并发度不是特别高的情况下,第二种(rocketmq优先推荐)和第四种方案为较优方案。
现有的分布式定时任务有,xxjob,elasticjob,springjob等。