spring-boot 分散式定時任務鎖shedlock
先做翻譯:
shedlock只做一件事,就是確保計劃任務最多同時執行一次;如果正在一個節點上執行任務,它將獲取一個鎖,以防止從另一個節點(或執行緒)執行相同任務。請注意,過去一個任務已在一個節點上執行,則其他節點上的執行不會等待,只會跳過它;
目前支援Mongo、JDBC資料庫、redis、hazelcast或zookeeper協調的spring scheduled task。
shedlock不是分散式排程框架,它是隻是一個鎖!!
用法(僅試了jdbcTemplate)
要求:java8、slf4j-api(官網說的)、spring框架(可選);
當然用shedlock就是為了用它鎖 spring自帶的 @Scheduled;
pom:
<dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>0.16.1</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>0.16.1</version> </dependency>
[email protected]註解:為方法加上鎖;name屬性(鎖的名稱)必須指定,每次只能執行一個具有相同名字的任務。
2.lockAtMostFor屬性,指定執行節點死亡時應該保留鎖的時間。這只是後備,正常情況下,鎖定會在任務完成後立即釋放。
還是不太理解這個屬性的作用;有懂的人可以留言~
明白了: 設定鎖的最大持有時間,為了解決如果持有鎖的節點掛了,無法釋放鎖,其他節點無法進行下一次任務。
設定了最大持有持有時間,當持有時間到了自動釋放鎖,不影響下一次執行;
其實就是設定鎖的歸還時間。
3.lockAtLeastFor
屬性,指定保留鎖的最短時間。主要目的是在任務非常短的且節點之間存在時鐘差異的情況下防止多個節點執行。這個屬性是鎖的持有時間。設定了多少就一定會持有多長時間,再次期間,下一次任務執行時,其他節點包括它本身是不會執行任務的。
例如:
假設您有一個每15分鐘執行一次的任務,通常需要幾分鐘才能執行。此外,您希望每15分鐘最多執行一次。在這種情況下,您可以像這樣配置它
import net.javacrumbs.shedlock.core.SchedulerLock;
...
private static final int FOURTEEN_MIN = 14 * 60 * 1000;
...
@Scheduled(cron = "0 */15 * * * *")
@SchedulerLock(name = "scheduledTaskName", lockAtMostFor = FOURTEEN_MIN, lockAtLeastFor = FOURTEEN_MIN)
public void scheduledTask() {
// do something
}
官網原話如下:
通過設定lockAtMostFor
我們確保即使節點死亡也釋放鎖定,並通過設定lockAtLeastFor
確保它在十五分鐘內不會執行多次。請注意,這lockAtMostFor
只是執行任務的節點死亡的情況下的安全網,因此將其設定為遠遠大於最大估計執行時間的時間。 如果任務需要的時間超過lockAtMostFor
,則會再次執行。
我的理解:
設定每15分鐘執行一次;
localAtLeastFor=14分鐘,就是說當前節點執行時,就會持有鎖14分鐘,原始碼預設給了0分鐘;
lockAtMostFor預設給了一小時;
別人的理解:
個人理解,拿JDBCTemplate進行說明,就是當第一個微服務執行定時任務的時候,會將此定時任務進行鎖操作,然後其他的定時任務就不會再執行,鎖操作有一定的時長,超過這個時長以後,再一次,所有的定時任務進行爭搶下一個定時任務的執行權利,如此迴圈。其中兩個配置lockAtMostFor和lockAtLeastFor,保證了在一個定時任務的區間內只有一個定時任務在執行,同時也保證了即便是其中的一個定時任務掛掉了,到一定的時間以後,鎖也會釋放,其他的定時任務依舊會進行執行權的爭奪,執行定時任務。
配置任務計劃程式
現在我們需要將庫整合到Spring中。它是通過包裝標準的Spring任務排程程式完成的。
@Configuration
@EnableScheduling
public class ShedlockConfig {
@Bean
public LockProvider lockProvider(DataSource dataSource) {
return new JdbcTemplateLockProvider(dataSource);
}
@Bean
public ScheduledLockConfiguration scheduledLockConfiguration(LockProvider lockProvider) {
return ScheduledLockConfigurationBuilder
.withLockProvider(lockProvider)
.withPoolSize(10)
.withDefaultLockAtMostFor(Duration.ofMinutes(10))
.build();
}
}
自己手動建立庫表,預設庫表是這樣,也可以自定義(未試);
CREATE TABLE shedlock(
name VARCHAR(64),
lock_until TIMESTAMP(3) NULL,
locked_at TIMESTAMP(3) NULL,
locked_by VARCHAR(255),
PRIMARY KEY (name)
)