1. 程式人生 > >ShedLock-輕量級分散式定時任務重複執行解決方案

ShedLock-輕量級分散式定時任務重複執行解決方案

什麼是ShedLock

ShedLock是一個在分散式環境中使用的定時任務框架,用於解決在分散式環境中的多個例項的相同定時任務在同一時間點重複執行的問題,解決思路是通過對公用的資料庫中的某個表進行記錄和加鎖,使得同一時間點只有第一個執行定時任務併成功在資料庫表中寫入相應記錄的節點能夠成功執行而其他節點直接跳過該任務。當然不只是資料庫,目前已經實現的支援資料儲存型別除了經典的關係型資料庫,還包括MongoDB,Zookeeper,Redis,Hazelcast。

如何使用

ShedLock採用非侵入式程式設計的思想,通過註解的方式來實現相應的功能。

首先引入Maven依賴

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

然後使用@SchedulerLock來對需要定時執行的任務進行註解。

import net.javacrumbs.shedlock.core.SchedulerLock;

...

@Scheduled(...)
@SchedulerLock(name = "scheduledTaskName")
public void scheduledTask() {
   // do something
}

@SchedulerLock註解一共支援五個引數,分別是

  • name 用來標註一個定時服務的名字,被用於寫入資料庫作為區分不同服務的標識,如果有多個同名定時任務則同一時間點只有一個執行成功
  • lockAtMostFor 成功執行任務的節點所能擁有獨佔鎖的最長時間,單位是毫秒ms
  • lockAtMostForString 成功執行任務的節點所能擁有的獨佔鎖的最長時間的字串表達,例如“PT14M”表示為14分鐘
  • lockAtLeastFor 成功執行任務的節點所能擁有獨佔所的最短時間,單位是毫秒ms
  • lockAtLeastForString 成功執行任務的節點所能擁有的獨佔鎖的最短時間的字串表達,例如“PT14M”表示為14分鐘

與Spring進行整合

需要配置兩個Bean,一個是lockProvider,一個是scheduler

<!-- lock provider of your choice (jdbc/zookeeper/mongo/whatever) -->
<bean id="lockProvider" class="net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider">
    <constructor-arg ref="dataSource"/>
</bean>

<bean id="scheduler" class="net.javacrumbs.shedlock.spring.SpringLockableTaskSchedulerFactoryBean">
    <constructor-arg>
        <task:scheduler id="sch" pool-size="10"/>
    </constructor-arg>
    <constructor-arg ref="lockProvider"/>
    <constructor-arg name="defaultLockAtMostFor">
        <bean class="java.time.Duration" factory-method="ofMinutes">
            <constructor-arg value="10"/>
        </bean>
    </constructor-arg>
</bean>

由於ShedLock使用了資料庫,所以還需要在資料庫中建立一張相應的表以供分散式環境中的各個節點進行加鎖解鎖。

與其他資料儲存的整合詳見作者的github

原理分析

ShedLock使用AOP代理的方式來實現。

可以通過對TaskScheduler類的繼承來實現使用者自定義的AOP行為。對於加了@SchedulerLock的方法都會在啟動時通過代理的方式加入框架所實現的分散式鎖功能。

image

@Bean
public TaskScheduler taskScheduler() {
    return new MySpecialTaskScheduler();
}

對比quartz

相比於quartz,ShedLock只提供了最基本的時間排程格式,而quartz可以提供更加豐富的可供自定義的時間排程方式,但是於quartz相比,ShedLock是輕量級的,通過註解的方式,把所有的一切都交給框架處理,使得程式碼不會受到影響,更加符合非侵入式程式設計的思想,使得程式碼更加簡潔明瞭。