用shedlock實現分布式定時任務鎖


spring的定時任務經常被各個服務用到,比如定時清理日志,定時提醒,

比較方便的就是用Scheduled注解了

簡單的配置一下就能用了

@EnableScheduling
@SpringBootApplication
public class ScheduledLockApplication {

    public static void main(String[] args) {
        SpringApplication.run(ScheduledLockApplication.class, args);
    }

}

  

這里每2秒打印一下當前時間

@Component
public class ScheduledLock
{
    @Scheduled(cron = "0/2 * * * * ?")
    public void run()
    {
        System.out.print(new Date().toString() + "\n");
    }
}

  

但是!

有一天服務的壓力過大,一個服務支撐不住了,我們要考慮部署多個服務來分散壓力

這時問題就來了

你突然發現你的定時系統,在各個服務上全她丫的跑起來了,做着同樣的事情,這必然不是我們想要的結果

 

這時你一定會想辦法,讓定時只執行一次

比如一個服務一個配置文件,在配置文件中控制定時的開關

再比如通過數據庫的讀寫來控制定時的開關

詳盡任何辦法,其實這些都是一些不錯的解決辦法

 

但是!

有一個更方便的東西

那就是shedlock

就叫她分布式定時任務鎖吧

 

她的鎖分好多種

Mongo,Redis,Hazelcast,ZooKeeper,還有所有帶JDBC的東西

 

這玩意用起來也特簡單

她的包

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-spring</artifactId>
    <version>2.2.0</version>
</dependency>

  

這里用JDBC的鎖

再添加一個包

<dependency>
    <groupId>net.javacrumbs.shedlock</groupId>
    <artifactId>shedlock-provider-jdbc-template</artifactId>
    <version>2.2.0</version>
</dependency>

 

對她進行一下配置,創建一個她要用的bean

@Configuration
public class ScheduledLockConfig
{
    @Bean
    public LockProvider lockProvider(DataSource dataSource) {
        return new JdbcTemplateLockProvider(dataSource);
    }
}

  

我用的mysql數據庫

在數據庫中添加一張名為shedlock表

這張表也是她要用的,她通過修改數據庫表中的數據實現鎖

里面有四個字段

主鍵name:每個定時任務的一個名字

locked_at:鎖的開始時間

lock_until:鎖的結束時間

再定時開始時,會更新這兩個時間,在時間之內的定時是不會被執行的

 

在啟動類上加上注解EnableSchedulerLock,開啟定時任務鎖,指定一個默認的鎖的時間

@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
@SpringBootApplication
public class ScheduledLockApplication {

    public static void main(String[] args) {
        SpringApplication.run(ScheduledLockApplication.class, args);
    }

}

  

在栗子中添加注解SchedulerLock

@Component
public class ScheduledLock
{
    private static final int lockTime = 1000;

    @Scheduled(cron = "0/2 * * * * ?")
    @SchedulerLock(name = "TaskScheduler_scheduledTask", lockAtMostFor = lockTime, lockAtLeastFor = lockTime)
    public void run()
    {
        System.out.print(new Date().toString() + "\n");
    }
}

  

這個注解有五個參數

name:定時任務的名字,就是數據庫中的內個主鍵
lockAtMostFor:鎖的最大時間單位為毫秒
lockAtMostForString:最大時間的字符串形式,例如:PT30S 代表30秒
lockAtLeastFor:鎖的最小時間單位為毫秒
lockAtLeastForString:最小時間的字符串形式

 

好了,起兩個項目讓她跑起來,看看結果

雖然不是很規律,但是沒有重復的時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM