Java中實現分散式定時任務的方法
定時器Scheduler在平時使用比較頻繁,在springboot中,配置好@Scheduled和@EnableScheduling之後,定時器就能正常執行,實現定時任務的功能。
但是在這樣的情況下:如果開發的服務需要水平部署實現負載均衡,那麼定時任務就會同時在多個服務例項上執行,那麼一方面,可能由於定時任務的邏輯處理需要訪問公共資源從而造成併發問題;另一方面,就算沒有併發問題,那麼一個同樣的任務多個服務例項同時執行,也會造成資源的浪費。因此需要一種機制來保證多個服務例項之間的定時任務正常、合理地執行。
本文以shedlock為例,來實現分散式定時任務的控制。
ShedLock可以保證多個同樣的定時任務在多個服務例項之間最多隻執行一次,是一個在分散式環境中保證定時任務合理執行的框架,我們可以叫它分散式定時任務鎖。
ShedLock的實現原理是採用公共儲存實現的鎖機制,使得同一時間點只有第一個執行定時任務的服務例項能執行成功,並在公共儲存中儲存"我正在執行任務,從什麼時候(預計)執行到什麼時候",其他服務例項執行時如果發現任務正在執行,則直接跳過本次執行,從而保證同一時間一個任務只被執行一次。
ShedLock的公共儲存目前支援的有:MonogoDynamoDBJdbcTemplateZooKeeper (using Curator)Redis (using Spring RedisConnectionFactory)Redis (using Jedis)Hazelcast第一步引入依賴
<!-- shedlock start --> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-spring</artifactId> <version>4.11.1</version> </dependency> <dependency> <groupId>net.javacrumbs.shedlock</groupId> <artifactId>shedlock-provider-jdbc-template</artifactId> <version>4.11.1</version> </dependency> <!-- shedlock end -->
第二步新增配置類
import net.javacrumbs.shedlock.core.LockProvider; import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.core.JdbcTemplate; import javax.annotation.Resource; import javax.sql.DataSource; import java.util.TimeZone; /** * @descrition shedlock配置類 * @since 2021-01-10 22:39 */ @Configuration public class ShedLockConfig { @Resource private DataSource dataSource; /** * @description * @date 2021/1/10 22:39 */ @Bean public LockProvider lockProvider() { return new JdbcTemplateLockProvider( JdbcTemplateLockProvider.Configuration.builder() .withJdbcTemplate(new JdbcTemplate(dataSource)) .withTimeZone(TimeZone.getTimeZone("GMT+8")) .build() ); } }
第三步,新增公共儲存,前面我們說過shedlock支援多種公共儲存作為鎖,本文我們以mysql為例
CREATE TABLE shedlock ( NAME VARCHAR ( 64 ) NOT NULL,lock_until TIMESTAMP ( 3 ) NOT NULL,locked_at TIMESTAMP ( 3 ) NOT NULL DEFAULT CURRENT_TIMESTAMP ( 3 ),locked_by VARCHAR ( 255 ) NOT NULL,PRIMARY KEY ( NAME ) );
第四步,新增具體任務類
import lombok.extern.slf4j.Slf4j; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Date; /** * @author shane * @date 2021/1/10 23:39 */ @Slf4j @Component public class TestJob { /** * @description 每隔1min列印一次 * @date 2021/1/10 23:39 */ @Scheduled(cron = "0 0/1 * * * ?") // lockAtMostFor為鎖預設持有時間,會覆蓋啟動類中的預設持有時間 @SchedulerLock(name = "demo",lockAtMostFor = "70m") public void print() throws InterruptedException { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//設定日期格式 log.warn("當前時間:"+df.format(new Date())); } }
接著,我們複製一份程式碼,分別啟動兩個例項來看結果資料庫記錄@SchedulerLock註解引數說明name:定時任務的名字,就是資料庫中的內個主鍵
lockAtMostFor:鎖的最大時間單位為毫秒
lockAtLeastFor:鎖的最小時間單位為毫秒
對了,還有啟動類的配置
@SpringBootApplication @MapperScan("com.example.test.mapper") @EnableScheduling @EnableSchedulerLock(defaultLockAtMostFor = "10m") // 預設的鎖的時間 public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class,args); } }
參考出處:
https://www.jianshu.com/p/941416645606
shedlock的github地址:https://github.com/lukas-krecan/ShedLock
到此這篇關於Java中實現分散式定時任務的方法的文章就介紹到這了,更多相關java分散式定時任務內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!