elastic-job-lite

ElasticJob 是一款分布式调度框架,支持数据分片和弹性伸缩。它通过 ZooKeeper 实现作业集群间的协调与分片,适用于大规模数据处理场景。本文介绍 ElasticJob 的核心概念、分片策略及调度模型。

前言

数据分片的目的在于把一个任务分散到不同的机器上运行,既可以解决单机计算能力上限的问题,也能降低部分任务失败对整体系统的影响。elastic-job并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。框架也预置了一些分片策略:平均分配算法策略,作业名哈希值奇偶数算法策略,轮转分片策略。同时也提供了自定义分片策略的接口。

调度模型

与大部分的作业平台不同,ElasticJob 的调度模型划分为支持线程级别调度的进程内调度 ElasticJob-Lite,和进程级别调度的 ElasticJob-Cloud。

  • 进程内调度(推荐)
    ElasticJob-Lite 是面向进程内的线程级调度框架。通过它,作业能够透明化的与业务应用系统相结合。 它能够方便的与 Spring 、Dubbo 等 Java 框架配合使用,在作业中可自由使用 Spring 注入的 Bean,如数据源连接池、Dubbo 远程服务等,更加方便的贴合业务开发。

  • 进程级调度
    独立布署,能够对作业服务器的资源进行控制,因此其作业类型可划分为常驻任务和瞬时任务。

Demo案例

根据官文档简写demo如下

//启动类
public final class JavaMain {
    
    private static final int EMBED_ZOOKEEPER_PORT = 2181;
    
    private static final String ZOOKEEPER_CONNECTION_STRING = "localhost:" + EMBED_ZOOKEEPER_PORT;
    
    private static final String JOB_NAMESPACE = "elasticjob-example-lite-java";
    
    private static final String EVENT_RDB_STORAGE_DRIVER = "org.h2.Driver";
    
    private static final String EVENT_RDB_STORAGE_URL = "jdbc:h2:mem:job_event_storage";
    
    private static final String EVENT_RDB_STORAGE_USERNAME = "sa";
    
    private static final String EVENT_RDB_STORAGE_PASSWORD = "";
    
    public static void main(final String[] args) throws IOException {
        //设置机器网卡,用来确定本机的唯一性
        System.setProperty("elasticjob.preferred.network.interface", "en0");
        //连接zk
        CoordinatorRegistryCenter regCenter = setUpRegistryCenter();
        //Tracing配置,通知形式记录任务调用过程
        TracingConfiguration<DataSource> tracingConfig = new TracingConfiguration<>("RDB", setUpEventTraceDataSource());
        //设置一个简单的任务
        setUpSimpleJob(regCenter, tracingConfig);
    }
    
    private static CoordinatorRegistryCenter setUpRegistryCenter() {
        ZookeeperConfiguration zkConfig = new ZookeeperConfiguration(ZOOKEEPER_CONNECTION_STRING, JOB_NAMESPACE);
        CoordinatorRegistryCenter result = new ZookeeperRegistryCenter(zkConfig);
        result.init();
        return result;
    }
    
    private static DataSource setUpEventTraceDataSource() {
        BasicDataSource result = new BasicDataSource();
        result.setDriverClassName(EVENT_RDB_STORAGE_DRIVER);
        result.setUrl(EVENT_RDB_STORAGE_URL);
        result.setUsername(EVENT_RDB_STORAGE_USERNAME);
        result.setPassword(EVENT_RDB_STORAGE_PASSWORD);
        return result;
    }
    
    private static void setUpSimpleJob(final CoordinatorRegistryCenter regCenter, final TracingConfiguration<DataSource> tracingConfig) {
        new ScheduleJobBootstrap(regCenter, new JavaSimpleJob(), JobConfiguration.newBuilder("javaSimpleJob", 3)
                .cron("0/5 * * * * ?").shardingItemParameters("0=Beijing,1=Shanghai,2=Guangzhou").build(), tracingConfig).schedule();
    }
    
}

//具体的任务
public class JavaSimpleJob implements SimpleJob {

    @Override
    @SneakyThrows
    public void execute(final ShardingContext shardingContext) {
        System.out.println(String.format("Item: %s | Time: %s | Thread: %s | %s",
                shardingContext.getShardingItem(), new SimpleDateFormat("HH:mm:ss").format(new Date()), Thread.currentThread().getId(), "SIMPLE"));

        Thread.sleep(80000);

    }
}

zk中注册数据如下
在这里插入图片描述

elastic-job原理

elastic-job的是通过zookeeper来实现的。从zookeeper数据看elastic-job是以任务为维度。任务和任务之间隔理的。

执行原理

elastic-job各节点读取配置文件,封装自己的ElasticJob注入Quazrt定时器框架,然后通过选主,分片等判断,最终执行JavaSimpleJob。

在这里插入图片描述

在这里插入图片描述

选主原理

选主主要通过zk机制选取,其原理请参考《分布式事务与一致性》。代码如是

//ElasticJobExecutor.execute (将Quazrt转为ElasticJob逻辑入口)
//LiteJobFacade.getShardingContexts 
//ShardingService.shardingIfNecessary
public void shardingIfNecessary() {
        //循环选主
        if (!leaderService.isLeaderUntilBlock()) {
            blockUntilShardingCompleted();
            return;
        }
        //等待进行中任务全部执行完毕,如果之前有任务还没跑完,全开始等待
        waitingOtherShardingItemCompleted();
        JobConfiguration jobConfig = configService.load(false);
        int shardingTotalCount = jobConfig.getShardingTotalCount();
        log.debug("Job '{}' sharding begin.", jobName);
        jobNodeStorage.fillEphemeralJobNode(ShardingNode.PROCESSING, "");
        resetShardingInfo(shardingTotalCount);
        JobShardingStrategy jobShardingStrategy = JobShardingStrategyFactory.getStrategy(jobConfig.getJobShardingStrategyType());
        //根据分片策略重新分片,然后结束选举,其它不是leader结点不用阻塞在选主那
        jobNodeStorage.executeInTransaction(new PersistShardingInfoTransactionExecutionCallback(jobShardingStrategy.sharding(availableJobInstances, jobName, shardingTotalCount)));
        log.debug("Job '{}' sharding complete.", jobName);
    }

总结

  1. elastic-job通过代理Quazrt实现。
  2. 新的Job实例加入集群,现有的Job实例下线都会触发重新选举
  3. 发生重新选举时,如果发现还有任务在跑,会等待其跑完,再重新分片

主要参考

ElasticJob
elastic-job详解(一):数据分片

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值