微服务中定时任务的重复执行问题

在微服务架构中,多个节点都单独部署了应用,那么对于应用中的定时任务应该如何避免重复执行呢?

从抽象层面而言,这似乎是一个并发问题,但实际上这是一个选举问题:

1.任务必须执行且仅执行一次(不能重复)

2.当某个微服务实例故障,其他实例仍然可以执行定时任务(故障转移)

3.当某个实例在执行任务过程中失败(补偿机制)此细节本文不做讨论

 

对于此类“分布式并发”场景,☝️🤓 诶!可以使用分布式锁Redisson方案。其实不然,正如我上面所述这是选举问题,而非并发问题。

Redisson解决的是并发问题(特别是高并发),此场景下的并发量取决于实例的数量,而且还受到实例之间时间偏差的影响。

因此,利用Redis的SETNX命令就已经足够应付此场景,无须引入更复杂的Redisson方案。

 

代码示例

@Component
public class ScheduleTask {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 每分钟执行
     */
    @Scheduled(cron = "0 * * * * ?")
    public void executeTask() {

        Boolean bool = stringRedisTemplate.opsForValue().setIfAbsent(GlobalConst.SCHEDULE_TASK, "lol", 30, TimeUnit.SECONDS);

        LocalDateTime now = LocalDateTime.now();

        if (Boolean.TRUE.equals(bool)) {
            System.out.println("定时任务执行了!当前时间:" + now);
        } else {
            // 锁获取失败,打印日志或记录
            System.out.println("定时任务未执行,因为未能获取锁。当前时间:" + now);
        }

    }
}

 

需要注意的是:

定时任务需要执行的时间一定要足够小于Redis对应key的持续时间(不能任务还未执行完,就提前释放锁)

Redis对应key的持续时间一定要接近定时任务循环周期时间(锁的持续时间尽量接近一个循环周期)

定时任务执行过程中发生异常时,如何触发补偿机制?或者是否需要监控定时任务一定执行成功了?MQ?

posted @ 2024-10-28 10:14  Ashe|||^_^  阅读(33)  评论(0编辑  收藏  举报