分布式调度框架Elastic-Job

分布式调度框架Elastic-Job

Elastic-Job介绍

Elastic-Job是当当⽹开源的⼀个分布式调度解决⽅案,基于Quartz⼆次开发的,由两个相互独⽴的⼦项⽬Elastic-Job-Lite和Elastic-Job-Cloud组成。我们要学习的是 Elastic-Job-Lite,它定位为轻量级⽆中⼼化解决⽅案,使⽤Jar包的形式提供分布式任务的协调服务,⽽Elastic-Job-Cloud⼦项⽬需要结合Mesos以及Docker在云环境下使⽤。
Elastic-Job的github地址:https://github.com/elasticjob
主要功能介绍

  • 分布式调度协调 在分布式环境中,任务能够按指定的调度策略执⾏,并且能够避免同⼀任务多实例重复执⾏
  • 丰富的调度策略 基于成熟的定时任务作业框架Quartz cron表达式执⾏定时任务
  • 弹性扩容缩容 当集群中增加某⼀个实例,它应当也能够被选举并执⾏任务;当集群减少⼀个实例时,它所执⾏的任务能被转移到别的实例来执⾏。
  • 失效转移 某实例在任务执⾏失败后,会被转移到其他实例执⾏
  • 错过执⾏作业重触发 若因某种原因导致作业错过执⾏,⾃动记录错过执⾏的作业,并在上次作业完成后⾃动触发。
  • ⽀持并⾏调度 ⽀持任务分⽚,任务分⽚是指将⼀个任务分为多个⼩任务项在多个实例同时执⾏。
  • 作业分⽚⼀致性 当任务被分⽚后,保证同⼀分⽚在分布式环境中仅⼀个执⾏实例。
Elastic-Job-Lite应⽤

jar包(API) + 安装zk软件
Elastic-Job依赖于Zookeeper进⾏分布式协调,所以需要安装Zookeeper软件(3.4.6版本以上),关于Zookeeper,此处我们不做详解,在阶段三会有深度学习,我们此处需要明⽩Zookeeper的本质功能:存储+通知。

安装Zookeeper(此处单例配置)
1)我们使⽤3.4.10版本,在linux平台解压下载的zookeeper-3.4.10.tar.gz
2)进⼊conf⽬录,cp zoo_sample.cfg zoo.cfg
3) 进⼊bin⽬录,启动zk服务

启动 ./zkServer.sh start
停⽌ ./zkServer.sh stop
查看状态 ./zkServer.sh status

Zookeeper的树形节点结构图

在这里插入图片描述
引⼊Jar包

<!-- https://mvnrepository.com/artifact/com.dangdang/elastic-job-lite-core
-->
<dependency>
 <groupId>com.dangdang</groupId>
 <artifactId>elastic-job-lite-core</artifactId>
 <version>2.1.5</version>
</dependency>

定时任务实例

需求:每隔两秒钟执⾏⼀次定时任务(resume表中未归档的数据归档到resume_bak表中,每次归档1条记录)
1)resume_bak和resume表结构完全⼀样
2)resume表中数据归档之后不删除,只将state置为"已归档"

数据表结构

-- ----------------------------
-- Table structure for resume
-- ----------------------------
DROP TABLE IF EXISTS `resume`;
CREATE TABLE `resume` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `name` varchar(255) DEFAULT NULL,
 `sex` varchar(255) DEFAULT NULL,
 `phone` varchar(255) DEFAULT NULL,
 `address` varchar(255) DEFAULT NULL,
 `education` varchar(255) DEFAULT NULL,
 `state` varchar(255) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8;
SET FOREIGN_KEY_CHECKS = 1;
程序开发

定时任务类

package elasticjob;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import util.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.List;
import java.util.Map;
public class BackupJob implements SimpleJob {
 // 定时任务每执⾏⼀次都会执⾏如下的逻辑
 @Override
 public void execute(ShardingContext shardingContext) {
 /*
 从resume数据表查找1条未归档的数据,将其归档到resume_bak
表,并更新状态为已归档(不删除原数据)
 */
 // 查询出⼀条数据
 String selectSql = "select * from resume where
state='未归档' limit 1";
 List<Map<String, Object>> list =
JdbcUtil.executeQuery(selectSql);
 if(list == null || list.size() == 0) {
 return;
 }
 Map<String, Object> stringObjectMap = list.get(0);
 long id = (long) stringObjectMap.get("id");
 String name = (String) stringObjectMap.get("name");
 String education = (String)
stringObjectMap.get("education");
 // 打印出这条记录
 System.out.println("======>>>id:" + id + " name:" +
name + " education:" + education);
 // 更改状态
 String updateSql = "update resume set state='已归档'
where id=?";
 JdbcUtil.executeUpdate(updateSql,id);
 // 归档这条记录
 String insertSql = "insert into resume_bak select *
from resume where id=?";
 JdbcUtil.executeUpdate(insertSql,id);
 }
}

主类

package elasticjob;
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
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.reg.base.CoordinatorRegistryCenter;
import
com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import
com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;
public class ElasticJobMain {
 public static void main(String[] args) {
 // 配置注册中⼼zookeeper,zookeeper协调调度,不能让任务重复执⾏,
通过命名空间分类管理任务,对应到zookeeper的⽬录
 ZookeeperConfiguration zookeeperConfiguration = new
ZookeeperConfiguration("localhost:2181","data-archive-job");
 CoordinatorRegistryCenter coordinatorRegistryCenter = new
ZookeeperRegistryCenter(zookeeperConfiguration);
 coordinatorRegistryCenter.init();
 // 配置任务
 JobCoreConfiguration jobCoreConfiguration =
JobCoreConfiguration.newBuilder("archive-job","*/2 * * * *
?",1).build();
 SimpleJobConfiguration simpleJobConfiguration = new
SimpleJobConfiguration(jobCoreConfiguration,BackupJob.class.getNam
e());
 // 启动任务
 new JobScheduler(coordinatorRegistryCenter,
LiteJobConfiguration.newBuilder(simpleJobConfiguration).build()).i
nit();
 }
}

JdbcUtil⼯具类

package util;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JdbcUtil {
 //url
 private static String url = "jdbc:mysql://localhost:3306/job?
characterEncoding=utf8&useSSL=false";
 //user
 private static String user = "root";
 //password
 private static String password = "123456";
 //驱动程序类
 private static String driver = "com.mysql.jdbc.Driver";
 static {
 try {
 Class.forName(driver);
 } catch (ClassNotFoundException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 }
 public static Connection getConnection() {
 try {
 return DriverManager.getConnection(url, user,
password);
} catch (SQLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }
 return null;
 }
 public static void close(ResultSet rs, PreparedStatement ps,
Connection con) {
 if (rs != null) {
 try {
 rs.close();
 } catch (SQLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } finally {
 if (ps != null) {
 try {
 ps.close();
 } catch (SQLException e) {
 // TODO Auto-generated catch block
e.printStackTrace();
 } finally {
 if (con != null) {
 try {
 con.close();
 } catch (SQLException e) {
 // TODO Auto-generated catch block
e.printStackTrace();
 }
 }
 }
 }
 }
 }
 }
 
 public static void executeUpdate(String sql,Object...obj) {
 Connection con = getConnection();
 PreparedStatement ps = null;
 try {
 ps = con.prepareStatement(sql);
 for (int i = 0; i < obj.length; i++) {
 ps.setObject(i + 1, obj[i]);
 }
 ps.executeUpdate();
 } catch (SQLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } finally {
 close(null, ps, con);
 }
 }
 
 public static List<Map<String,Object>> executeQuery(String
sql, Object...obj) {
 Connection con = getConnection();
 ResultSet rs = null;
 PreparedStatement ps = null;
 try {
 ps = con.prepareStatement(sql);
 for (int i = 0; i < obj.length; i++) {
 ps.setObject(i + 1, obj[i]);
 }
 rs = ps.executeQuery();
 
 List<Map<String, Object>> list = new ArrayList<>();
 
 int count = rs.getMetaData().getColumnCount();
 
 while (rs.next()) {
 
 Map<String, Object> map = new HashMap<String,
Object>();
 for (int i = 0; i < count; i++) {
 Object ob = rs.getObject(i + 1);
 String key = rs.getMetaData().getColumnName(i
+ 1);
 map.put(key, ob);
 }
 list.add(map);
 }
 return list;
 } catch (SQLException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 } finally {
 close(rs, ps, con);
 }
 return null;
 }
}

Elastic-Job-Lite轻量级去中心化的特点

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Elastic-Job是一个分布式任务调度框架,基于ZooKeeper实现了分布式任务协调和调度。它的原理可以概括为以下几个步骤: 1. 注册中心的连接:Elastic-Job通过连接ZooKeeper注册中心来进行任务的注册和协调。每个任务节点都会在注册中心进行注册,以便其他节点可以发现和协调任务。 2. 任务的分片:Elastic-Job任务分成多个片段(shard),每个片段由一个或多个任务节点执行。分片的目的是将任务拆分成多个部分,以便并行执行和负载均衡。 3. 任务调度Elastic-Job根据任务配置调度表达式(cron表达式)来触发任务的执行。调度器会根据表达式计算下一次任务执行的时间,并通知对应的任务节点执行任务。 4. 任务的协调:在多节点环境下,Elastic-Job通过ZooKeeper实现了分布式锁和协调机制,确保同一时间只有一个节点执行特定的任务片段。其他节点会等待锁释放后再去执行其他片段。 5. 任务的执行:任务节点收到调度器的通知后,根据配置任务逻辑执行具体的业务逻辑。每个节点只负责执行自己被分配到的任务片段。 6. 任务的监控和统计:Elastic-Job提供了丰富的监控和统计功能,可以通过控制台或API获取任务的执行情况、成功率、失败率等信息,方便进行任务的管理和监控。 通过以上步骤,Elastic-Job实现了分布式任务调度和执行,并提供了高可用、负载均衡、故障恢复等功能,使得分布式任务的开发和管理变得更加简单和可靠。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值