前言
急速入門,分佈式框架O(∩_∩)O哈哈~
Elastic-Job
分佈式調度解決方案,使用jar包提供協調服務
https://mvnrepository.com/search?q=elastic-job-lite-core
- 需要注意的是,我們在使用Elastic-Job時需要整合ZooKeeper集羣。
本地使用Windows版本ZooKeeper,單機版
- 單機啓動
- 修改配置文件
- 雙擊啓動
- (*❦ω❦)成功
Elastic-Job 分片
一個任務拆分成多個獨立的任務項,每個服務獲得一個或幾個分片項。
- 【案例:】
如果遍歷數據庫某張表的作業,供兩臺服務器。
每臺服務器執任務的50%,即服務器A執行ID尾號爲奇數的數據,服務器B執行ID尾號爲偶數的數據。
高可用
分片總數設置爲1,多於1臺服務器執行作業,1主n從。
執行服務器崩潰後,等待的服務器將啓動,執行下次任務。
Demo演示
Simple作業詳解
意爲定時任務的簡單實現,只需實現execute方法。提供了彈性的擴容和分片功能。
1.搭建項目
2.引入maven依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zcw</groupId>
<artifactId>zcw-java-simple-job</artifactId>
<version>1.0-SNAPSHOT</version>
<name>zcw-java-simple-job</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--Elastic-job-lite-core-->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId>
<version>2.1.5</version>
</dependency>
</dependencies>
</project>
3.實現SimpleJob接口,實現execute方法
package com.zcw.job;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
/**
* @ClassName : MySimpleJob
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-04 13:45
*/
public class MySimpleJob implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
System.out.println("我是當前分片項"+shardingContext.getShardingItem()+
",總分片項:"+shardingContext.getShardingTotalCount());
}
}
4.配置作業
- 定義作業核心配置(作業名稱,定時策略,分片總數)
- 定義作業類型(Simple,Dataflow,Scripe,實現類的全包名)
- 定義Lite作業根配置(overwrite屬性的重要性)
5.配置zookeeper的鏈接方式(單機版)
package com.zcw;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.JobTypeConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.lite.internal.schedule.JobScheduleController;
import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import com.zcw.job.MySimpleJob;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args ) {
System.out.println( "Hello World!" );
new JobScheduler(zkCenter(),configuration()).init();
}
/**
* 註冊中心
* @return
*/
public static CoordinatorRegistryCenter zkCenter(){
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("localhost:2181",
"zcw-simple-job");
CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
//註冊中心初始化
coordinatorRegistryCenter.init();
return coordinatorRegistryCenter;
}
/**
* Job配置
* @return
*/
public static LiteJobConfiguration configuration(){
//job核心配置
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("mySimpleJob","0/10 * * * * ?",2)
.build();
//job類型配置
JobTypeConfiguration jobTypeConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,
MySimpleJob.class.getCanonicalName());
//job根的配置(LiteJobConfiguration)
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration
.newBuilder(jobTypeConfiguration)
//啓動時都要覆蓋掉,註冊中心的數據
.overwrite(true)
.build();
return liteJobConfiguration;
}
}
- 運行
6.複製代碼, 修改端口,模擬兩臺服務器
dataflow流式任務
-
分爲數據抓取(fetchData)和數據處理(processData)
-
流程
1.定時任務根據規則觸發
2.抓取數據
3.處理數據
4.處理完數據後,再次抓取
5.若數據存在,繼續處理,若不存在,則本次任務結束
6.等待任務規則,下次觸發
- 應用場景:
不間歇的數據處理(比如:第三方訂單的抓取) - Demo練習
【實現DataflowJob接口】
注意:DataFlowJob泛型
泛型規定了抓取數據的返回類型
1.創建實體類
package com.zcw.model;
/**
* @ClassName : Order
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-04 17:37
*/
public class Order {
private Integer orderId;
//0 未處理;1,已處理
private Integer status;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", status=" + status +
'}';
}
}
2.編寫接口
package com.zcw.job;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.dataflow.DataflowJob;
import com.sun.org.apache.xpath.internal.operations.Or;
import com.zcw.model.Order;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName : MyDataflowJob
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-04 17:36
*/
public class MyDataflowJob implements DataflowJob<Order> {
private List<Order> orders = new ArrayList<>();
{
for(int i=0;i<100;i++){
Order order = new Order();
order.setOrderId(i+1);
order.setStatus(0);
orders.add(order);
}
}
@Override
public List<Order> fetchData(ShardingContext shardingContext) {
//訂單號 % 分片總數 == 當前分片項
List<Order> orderList = orders.stream().filter(o->o.getStatus()==0)
.filter(o->o.getOrderId()%shardingContext
.getShardingTotalCount() ==shardingContext.getShardingItem())
.collect(Collectors.toList());
List<Order> subList=null;
if(orderList!=null && orderList.size()>0){
subList = orderList.subList(0,10);
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime time = LocalTime.now();
System.out.println(time+",我是分片項:"+shardingContext.getShardingItem()+"," +
"我抓取的數據是:"+subList);
return subList;
}
@Override
public void processData(ShardingContext shardingContext, List<Order> list) {
list.forEach(o->o.setStatus(1));
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime time = LocalTime.now();
System.out.println(time+",我是分片項:"+shardingContext.getShardingItem()+
",我正在處理數據");
}
}
- 修改啓動類
package com.zcw;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.JobTypeConfiguration;
import com.dangdang.ddframe.job.config.dataflow.DataflowJobConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.lite.internal.schedule.JobScheduleController;
import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
import com.zcw.job.MyDataflowJob;
import com.zcw.job.MySimpleJob;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args ) {
System.out.println( "Hello World!" );
// new JobScheduler(zkCenter(),configuration()).init();
new JobScheduler(zkCenter(),configurationDataflow()).init();
}
/**
* 註冊中心
* @return
*/
public static CoordinatorRegistryCenter zkCenter(){
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("localhost:2181",
"zcw-simple-job");
CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
//註冊中心初始化
coordinatorRegistryCenter.init();
return coordinatorRegistryCenter;
}
/**
* Job配置
* @return
*/
public static LiteJobConfiguration configuration(){
//job核心配置
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("mySimpleJob","0/10 * * * * ?",2)
.build();
//job類型配置
JobTypeConfiguration jobTypeConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,
MySimpleJob.class.getCanonicalName());
//job根的配置(LiteJobConfiguration)
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration
.newBuilder(jobTypeConfiguration)
//啓動時都要覆蓋掉,註冊中心的數據
.overwrite(true)
.build();
return liteJobConfiguration;
}
/**
* Job配置
* @return
*/
public static LiteJobConfiguration configurationDataflow(){
//job核心配置
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("myDataFlowJob","0/10 * * * * ?",2)
.build();
//job類型配置
JobTypeConfiguration jobTypeConfiguration = new DataflowJobConfiguration(
jobCoreConfiguration,
MyDataflowJob.class.getCanonicalName(),true);
//job根的配置(LiteJobConfiguration)
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration
.newBuilder(jobTypeConfiguration)
//啓動時都要覆蓋掉,註冊中心的數據
.overwrite(true)
.build();
return liteJobConfiguration;
}
}
- 測試:
編寫腳本Script
echo 我是cmd腳本,我的作業信息是:%1
- 在我們APP類裏面定義方法
public static LiteJobConfiguration configurationScript(){
//job核心配置
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("myScriptJob","0/10 * * * * ?",2)
.build();
//job類型配置
JobTypeConfiguration jobTypeConfiguration = new ScriptJobConfiguration(
jobCoreConfiguration,
"F:/test/test.cmd");
//job根的配置(LiteJobConfiguration)
LiteJobConfiguration liteJobConfiguration = LiteJobConfiguration
.newBuilder(jobTypeConfiguration)
//啓動時都要覆蓋掉,註冊中心的數據
.overwrite(true)
.build();
return liteJobConfiguration;
}
- 運行
- 修改文件