1 数据量评估
定时任务一般的使用场景是定时查询出一批数据,对这一批数据进行业务操作。

根据数据量的大小决定是否使用分布式任务,如果数据量不大或者实时性要求不高,单机任务就够了,也可以减少相应复杂度。

如果数据量大就需要部署分布式任务。分布式集群中的节点对数据进行分片处理,即每个节点拿一部分数据进行业务处理。

2 仅解决并发问题方案
(1) Quartz + 分布式锁

假设定时任务部署了3台机器,在任务启动时3台机器竞争分布式锁,谁竞争到谁就执行,剩下2台不执行。分布式锁可以使用Redis或者Zookeeper

(2) 开关方案

方案一:配置文件中设置开关是否开启,执行任务前读取该开关,开启则执行。这种方式实现比较简单,但是如果需要换另外一台机器执行,必须修改配置项并发布项目,维护成本较高

方案二:建一个数据库配置表,配置表中配置可执行任务的机器标识,每台机器执行前读取这个配置,看看是否是本机。如果是则执行,否则不执行

方案三:Zookeeper做一个全局配置,配置项内容是可执行任务的机器标识,执行原理同方案一

3 真正分布式任务方案
(1) Quartz官方分布式方案

我认为这种方式比较重,需要根据官方文档新建数据表,个人并不推荐

(2) Elastic Job

当当网开源的一个分布式调度解决方案,在业界比较通用

(3) 自研分布式任务平台

有一定技术实力的公司,可以选择自研分布式任务平台
————————————————
利用redis分布式锁解决集群下定时任务重复执行

最近在给服务器搭建集群nginx的时候遇到了一个问题,mysql主从也搭建好了。其中有一个定时任务的问题,由于是主从两台机器,程序需要用nginx做反向代理,两台服务器都需要部署相同的程序,这样的话,每台服务器都有可能执行定时任务,导致定时任务重复执行,出现错乱的脏数据。研究了好久终于找到 了解决方案。

这个问题对于新手来说确实是一个挑战。不废话直接入正题。

解决方案是利用redis 的分布式锁来加锁。具体的方案入下:

1.  springboot的 yml文件需要配置redis 相关信息:

具体的yml中怎么配置redis百度即可,这里不多说!

2.  定时器中生命锁和key的名字

3.  业务逻辑部分:

public  void   执行方法(){
 
    boolean lock = false;
        try {
            //这里利用redis的分布式锁机制控制集群环境下定时器重复执行的问题
            lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
            logger.info("是否获取到锁:" + lock);
            if (lock) {
                //这里就是你自己的业务信息。
 
 
            } else {
                logger.info("没有获取到锁,不执行任务!");
                return;
            }
        } finally {
            if (lock) {
                redisTemplate.delete(KEY);
                logger.info("任务结束,释放锁!");
            } else {
                logger.info("没有获取到锁,无需释放锁!");
            }
        }
    }
}
 

写到这里基本就结束了。经过本人测试,目前没有发现问题。
————————————————
 

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐