本文介绍了在分布式环境中确保定时任务只由一台服务器执行的多种方法,包括数据库记录、Shedlock库、Redis分布式锁以及Redission的分布式锁实现。Shedlock提供了一种在Spring/SpringBoot项目中防止定时任务并发执行的解决方案,而Redis和Redission则是通过键值存储系统实现锁机制。推荐使用Redission,因为它提供了更完善的分布式锁功能。 摘要生成于 ,由 DeepSeek-R1 满血版支持,

如果只让一个服务器有定时代码,部署麻烦,需要多套代码,万一该机器挂了就完犊子了。

一般解决办法有如下几种:

数据库实现;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁;4.利用quartz集群分布式

1.数据库实现

(1)数据库建立一个表,用来记录uuid(或ip)和插入时间;

(2)当多个服务器执行定时任务的时候先生成个uuid把uuid(或服务器ip)和当前时间插入表里;

(3)表中查询当天最早的插入时间那条记录返回,与uuid(或服务器自己的ip)对比;

(4)若服务器自己的uuid(或ip)与数据库查询的uuid(ip)匹配则执行,不匹配则不执行;

2.使用Shedlock库

Shedlock库可以确保你的定时任务最多同时执行一次。如果一个任务正在一个节点上执行,它会获取一个锁,以防止从另一个节点(或线程)执行相同的任务。
Shedlock库的github地址:
Shedlock
示例:

2.1 对于spring或者springboot项目:

@Scheduled(cron = "0 */15 * * * *")
@SchedulerLock(name = "scheduledTaskName")
public void scheduledTask() {
   // do something

2.2 对于没有使用框架的项目:

LockingTaskExecutor executor = new DefaultLockingTaskExecutor(lockProvider);
     ...
Instant lockAtMostUntil = Instant.now().plusSeconds(600);
executor.executeWithLock(runnable, new LockConfiguration("lockName", lockAtMostUntil));

3.Redis的分布式锁实现

(1) 每个服务器生成随机uuid

(2) 利用redis的Setnx命令将随机uuid作为value存入redis

(3) 获取redis的value,与生成的随机uuid对比;

(4) value与生成的随机uuid匹配则执行,不匹配则不执行;

4.Redission的分布式锁来实现(推荐)

Redisson 是 redis 官网推荐实现分布式锁的一个第三方类库,通过开启另一个服务,后台进程定时检查持有锁的线程是否继续持有锁了。
4.1 引入maven

		<dependency>
			<groupId>org.redisson</groupId>
			<artifactId>redisson</artifactId>
			<version>3.19.1</version>
		</dependency>

4.2 测试代码

    public RedissonClient getRedissonClient() {
        // 默认连接地址 127.0.0.1:6379
        RedissonClient redisson = Redisson.create();
//        Config config = new Config();
//        config.useSingleServer().setAddress("redis://" + redisAddress); //redis服务器地址
//                .setDatabase(0) //制定redis数据库编号
//                .setUsername("").setPassword() // redis用户名密码
//                .setConnectionMinimumIdleSize(10) //连接池最小空闲连接数
//                .setConnectionPoolSize(50) //连接池最大线程数
//                .setIdleConnectionTimeout(60000) //线程的超时时间
//                .setConnectTimeout(6000) //客户端程序获取redis链接的超时时间
//                .setTimeout(60000) //响应超时时间
//        RedissonClient redisson = Redisson.create(config);
        return redisson;
    public void test() {
        //获取配置
        RedissonClient redissonClient = getRedissonClient();
        //获取锁对象
        RLock lock = redissonClient.getLock("myLock");
        lock.lock();
        //尝试获取锁 。尝试获取锁的最大等待时间为20秒(超过20秒则认为获取锁失败),只锁定10秒(超过10秒自动解锁,应设置锁定时间大于业务处理的时间)
        boolean res = lock.tryLock(20, 10, TimeUnit.SECONDS);
        //获取锁成功才执行业务代码
        if (res) {
            try {
            //这里编写业务逻辑代码
            ...
            } finally {
                lock.unlock();

参考:
Spring Scheduled Task running in clustered environment
How can you make a cluster run a task only once
集群服务器定时任务重复执行的解决方案
Redis分布式锁解析
分布式环境下定时任务如何做到只执行一次
Redisson分布式锁
Redis分布式锁-这一篇全了解(Redission实现分布式锁完美方案)
Distributed locks and synchronizers
Redis实现分布式锁

先说一下我们的系统, 在65和66上分别部署有weblogic节点,共计四个,在项目中我们的定时器会隔一段时间就从其它的五个系统中取数据,这时就出现了问题,本来取一次数据就可以的,现在重复执行了三次,同时还造成了对方服务器的压力。 现在说一下我们项目怎么解决的这个问题: 1、首先想到的是在定时执行任务这个文件中添加ip地址,固定成某一台能执行,但我们一台服务器上有两个节点,...
问题背景:当我们有多个服务器,每个服务器上都有相同的定时任务,如每天凌晨定时插入数据,如果多个服务器上的定时任务执行了会导致数据重复,如果只让一个服务器存在定时任务代码,部署起来比较麻烦,需要套代码,万一定时任务器宕这会导致系统不稳定性 一般解决方案有如下几种: 数据库实现 基于 Redis 的分布式锁 利用 quartz 集群分布式 数据库实现 数据库建立一个定时表,记录 IP 和插入时间 当多个服务器通知执行任务时把自己的 IP 和当前时间插入定时表 定时表中查询当天最早插入的时间那条记录
需求,由于现在定时任务,bash项目单部署压力过大、效率太低,现需要部署,并且当前时刻只能有一个定时任务成功执行。 3 JAVA demo环境概述 启3个springboot项目,端口不一致,定时任务代码一致。 当前任务获取锁,如果获取到锁,则执行任务,如果获取不到,则什么都不干。 Code: 检测任务:日志: 检测结果: 问题: 由于任务执行的时间很短,A节点抢到锁释放锁完成了,B节点抢锁去发现就没有锁,导致上报任务重复执行。 检测任务:日志: 检测结果:没有重复任务缺陷: 如果节点A抢到锁,
原文链接https://zhuanlan.zhihu.com/p/97068262 https://blog.csdn.net/J_Shine/article/details/80406743 1.使用redis分布式锁,为定时任务唯一指定的key加锁,并设置锁超时时间。当触发定时任务时,通过setNX(key,value)方法为唯一的key加锁,如果当前key不存在,将放入缓...
github教程链接:https://github.com/lukas-krecan/ShedLock 1、在数据执行脚本,SQL脚本链接 https://github.com/lukas-krecan/ShedLock#jdbctemplate 以下为PG数据库 CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP NOT NULL, locked_at TIMESTAMP NOT NULL, locked_by