分佈式任務調度

1 任務調度

定時JOB,在什麼時間進行執行代碼任務。

1.1 使用線程方式

public static void main(String[] args) {
		Runnable runnable = new Runnable() {
			@Override
			public void run() {
				while (true) {
					try {
						Thread.sleep(1000);
						count++;
						System.out.println(count);
					} catch (Exception e) {
						// TODO: handle exception
					}
				}
			}
		};
		Thread thread = new Thread(runnable);
		thread.start();
	}

1.2 timerTask

public static void main(String[] args) {
		TimerTask timerTask = new TimerTask() {

			@Override
			public void run() {
				count++;
				System.out.println(count);
			}
		};
		Timer timer = new Timer();
		// 天數
		long delay = 0;
		// 秒數
		long period = 1000;
		timer.scheduleAtFixedRate(timerTask, delay, period);
	}

1.3 線程池

	public static void main(String[] args) {
		Runnable runnable = new Runnable() {
			public void run() {
				// task to run goes here
				System.out.println("Hello !!");
			}
		};
		ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
		// 第二個參數爲首次執行的延時時間,第三個參數爲定時執行的間隔時間
		service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
	}

1.4 quartz

依賴:

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>

任務:

public class JobTask implements Job {
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("quartz job date: "+new Date().getTime());
    }
}

啓動類:

    public static void main(String[] args) throws SchedulerException {
        //1、創建scheduler的工廠
        StdSchedulerFactory stdSchedulerFactory = new StdSchedulerFactory();
        //2、從工廠中獲取調度器實例
        Scheduler scheduler = stdSchedulerFactory.getScheduler();
        //3、創建JobDetail
        JobDetail jobDetail = JobBuilder.newJob(JobTask.class)
                .withDescription("this is a quartz job")
                .withIdentity("quartzJob", "quartzGroup")
                .build();
        //任務運行的時間、simpleSchedule類型觸發器有效
        long time=System.currentTimeMillis()+5*1000;//5秒後
        Date startTime=new Date(time);
        //創建trigger
        //使用SimpleScheduleBuilder或者CronScheduleBuilder
        Trigger trigger = TriggerBuilder.newTrigger()
                .withDescription("quartz trigger")
                .withIdentity("quartzTrigger", "quartzTriggerGroup")
                .startAt(startTime)
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
                .build();
        //5、註冊任務和定時器
        scheduler.scheduleJob(jobDetail,trigger);
        //啓動
        scheduler.start();
    }

2 分佈式任務調度

雖然以上是可以實現任務調度,但是一般情況下這個應用是要部署在多個tomcat服務器上的,那麼又怎麼保證冪等性(對於一個job,不可能每臺服務器都讓他執行一次嘛,這不就重複執行了嗎)呢。

1、使用分佈式鎖,保證只有一臺服務器在執行

2、添加配置文件標識,兩臺服務器的配置文件不同,根據配置文件不同進行任務的調度,缺點是,那這就不支持集羣 了。

3、數據庫唯一標識,比如根據某一字段爲TRUE標識可以執行,執行時改爲FALSE,執行完後再改爲TRUE,缺點是經常操作數據庫,效率低

4、使用分佈式任務調度平臺XXLJOB

總的來說傳統的任務調度有很多缺點:

1、沒有補償機制(比如某個任務調度失敗後,只能等待下次調度或者人工調度)

2、不支持集羣

3、不支持路由策略

4、統計(每個服務或者項目都有自己的任務調度,肯定是要統計一些成功啊失敗什麼的,傳統調度的話只能自己管理自己的,可是這種任務調度的話最好是採用集中管理比較好)

5、管理平臺(沒有提供一個集中管理所有任務調度的平臺)

6、報警郵箱(比如說重試N次以後,都不成功那就發瘋郵件吧)、狀態監控(運行、結束、等待)

而以上這些在分佈式調度平臺XXLJOB都有支持。

2.1 XXL-JOB執行原理

首先對於任何一個客戶端的任務,需要註冊到xxl-job的admin平臺,然後admin將任務分發到各個執行器去執行,這裏選擇每個執行器的原理類似負載均衡策略。

實戰演練一下:

1、首先下載XXL-JOB

2、使用開發工具eclipse或者idea導入該項目

3、找到master/doc下的數據庫文件導入數據庫比如xx-job

4、修改配置文件xxl-job-admin.properties中數據庫的鏈接地址和密碼,這裏如果有自己搭建郵箱服務器也可填寫郵箱服務器等信息

5、將該項目部署到tomcat服務器進行啓動,訪問http://127.0.0.1:8081/,輸入密碼用戶名(默認admin,123456)

6、在web頁面中新建執行器以及任務

7、根據他提供的一些例子比如spring boot的,導入他的依賴以及配置文件這些信息到自己的項目中

8、填寫好admin部署的項目地址,這點很重要,指定執行器名稱、ip、端口、以及日誌文件路徑

9、記住XxlJobConfig這個配置文件一定要導入

10、新建一個Handler類似這樣

/**
 * 任務Handler的一個Demo(Bean模式)
 *
 * 開發步驟: 1、繼承 “IJobHandler” ; 2、裝配到Spring,例如加 “@Service” 註解; 3、加 “@JobHander”
 * 註解,註解value值爲新增任務生成的JobKey的值;多個JobKey用逗號分割; 4、執行日誌:需要通過 "XxlJobLogger.log"
 * 打印執行日誌;
 *
 * @author xuxueli 2015-12-19 19:43:36
 */
@JobHander(value = "demoJobHandler")//這個對應admin中的對應執行器中的任務的名稱
@Service
public class DemoJobHandler extends IJobHandler {
	@Value("${xxl.job.executor.port}")
	private String port;

	@Override
	public ReturnT<String> execute(String... params) throws Exception {//任務執行的代碼
		XxlJobLogger.log("XXL-JOB, Hello World." + port);
		System.out.println("XXL-JOB, Hello World." + port);
		for (int i = 0; i < 5; i++) {
			XxlJobLogger.log("beat at:" + i);
			// TimeUnit.SECONDS.sleep(2);
		}
		return ReturnT.SUCCESS;
	}

}

啓動項目後即可。這個是一個分佈式job調度平臺,可以試着啓動多個項目然後添加到同一個執行器中執行,按照他的規則填好集羣中的ip即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章